[test] Further tests for array:get

[test] Further tests for array:get

xquery version "3.1";

(:~
 : Tests for the array datatype and associated functions.
 :)
module namespace arr="http://exist-db.org/test/arrays";

declare namespace test="http://exist-db.org/xquery/xqsuite";
declare namespace output="http://www.w3.org/2010/xslt-xquery-serialization";
declare namespace json="http://www.json.org";

declare variable $arr:SERIALIZE_JSON :=
    <output:serialization-parameters>
        <output:method>json</output:method>
        <output:indent>no</output:indent>
    </output:serialization-parameters>;

declare variable $arr:SERIALIZE_JSON_INDENT :=
    <output:serialization-parameters>
        <output:method>json</output:method>
        <output:indent>yes</output:indent>
    </output:serialization-parameters>;

declare variable $arr:COLLECTION_CONF :=
    <collection xmlns="http://exist-db.org/collection-config/1.0">
        <index xmlns:xs="http://www.w3.org/2001/XMLSchema">
            <create qname="a" type="xs:int"/>
            <range>
                <create qname="b" type="xs:int"/>
            </range>
        </index>
        <triggers>
            <trigger class="org.exist.extensions.exquery.restxq.impl.RestXqTrigger"/>
        </triggers>
    </collection>;

declare variable $arr:XML_STORED :=
    <test>
        1
        2
    </test>;

declare variable $arr:RESTXQ_TEST :=
    'xquery version "3.1";

     module namespace rt="http://exist-db.org/restxq/rt";

     declare namespace rest="http://exquery.org/ns/restxq";
     declare namespace output="http://www.w3.org/2010/xslt-xquery-serialization";

     declare
         %rest:GET
         %rest:path("/arrays-test")
         %output:method("json")
         %rest:produces("application/json")
     function rt:json-test() {
         map {
             "status": "ok",
             "counters": array { 1 to 10 }
         }
     };';

declare variable $arr:primes := [2, 3, 5, 7, 11, 13, 17, 19];

declare
    %test:setUp
function arr:setup() {
    let $json := '[{"key1": "value1", "key2": "value2", "key1": "value3"}]'
    let $coll := xmldb:create-collection("/db", "array-test")
    let $confColl := xmldb:create-collection("/db/system/config/db", "array-test")
    return (
        xmldb:store($confColl, "collection.xconf", $arr:COLLECTION_CONF),
        xmldb:store($coll, "test.json", $json),
        xmldb:store($coll, "test.xml", $arr:XML_STORED),
        xmldb:store($coll, "test.xql", $arr:RESTXQ_TEST),
        sm:chmod(xs:anyURI($coll || "/test.xql"), "r-xr-xr-x")
    )
};

declare
    %test:tearDown
function arr:cleanup() {
    xmldb:remove("/db/array-test"),
    xmldb:remove("/db/system/config/db/array-test")
};

declare
    %test:args(1)
    %test:assertEquals(13)
    %test:args(3)
    %test:assertEquals(14)
function arr:function-item($pos as xs:int) {
    [13, 10, 14]($pos)
};

declare
    %test:args(1)
    %test:assertEquals(13)
    %test:args(3)
    %test:assertEquals(14)
function arr:function-item2($pos as xs:int) {
    let $a := [13, 10, 14]
    return
        $a($pos)
};

declare
    %test:args(1)
    %test:assertEquals(13)
    %test:args(3)
    %test:assertEquals(14)
function arr:function-item3($pos as xs:int) {
    let $a := [13, 10, 14]
    let $f := function($array as function(*), $position as xs:int) {
        $array($position)
    }
    return
        $f($a, $pos)
};

declare
    %test:assertError("FOAY0001")
function arr:function-item-out-of-bounds() {
    let $a := [13, 10, 14]
    return
        $a(22)
};

declare
    %test:assertError("err:XPTY0004")
function arr:function-item-invalid() {
    let $a := [13, 10, 14]
    return
        $a("x")
};

declare
    %test:assertError("FOAY0001")
function arr:get-item-out-of-bounds-positive() {
    let $a := [13, 10, 14]
    return
        array:get($a, 4)
};

declare
    %test:assertError("FOAY0001")
function arr:get-item-out-of-bounds-positive-large() {
    let $a := [13, 10, 14]
    return
        array:get($a, 22)
};

declare
    %test:assertError("FOAY0001")
function arr:get-item-out-of-bounds-zero() {
    let $a := [13, 10, 14]
    return
        array:get($a, 0)
};

declare
    %test:assertError("FOAY0001")
function arr:get-item-out-of-bounds-negative() {
    let $a := [13, 10, 14]
    return
        array:get($a, -1)
};

declare
    %test:pending("eXist-db does not correctly detect the type error. This is likely a larger issue than just arrays.")
    %test:assertError("XPTY0004")
function arr:get-invalid-type() {
    let $a := [13, 10, 14]
    return
        array:get($a, xs:double(0.1))
};

declare
    %test:assertEquals(13)
function arr:get-first() {
    let $a := [13, 10, 14]
    return
        array:get($a, 1)
};

declare
    %test:assertEquals(14)
function arr:get-last() {
    let $a := [13, 10, 14]
    return
        array:get($a, 3)
};

declare
    %test:args(1)
    %test:assertEmpty
    %test:args(2)
    %test:assertEquals(27, 17, 0)
function arr:square-constructor1($pos as xs:int) {
    let $a := [(), (27, 17, 0)]
    return $a($pos)
};

declare
    %test:args(1)
    %test:assertEquals("
test
")
    %test:args(2)
    %test:assertEquals(55)
function arr:square-constructor2($pos as xs:int) {
    let $a := [
test
, 55]
    return $a($pos)
};

declare
    %test:assertEquals(0)
function arr:square-constructor3() {
    let $a := []
    return array:size($a)
};

declare
    %test:args(1)
    %test:assertEquals(27)
    %test:args(2)
    %test:assertEquals(17)
function arr:curly-constructor1($pos as xs:int) {
    let $x := (27, 17, 0)
    let $a := array { $x }
    return $a($pos)
};

declare
    %test:args(1)
    %test:assertEquals(27)
    %test:args(2)
    %test:assertEquals(17)
function arr:curly-constructor2($pos as xs:int) {
    let $a := array { (), (27, 17, 0) }
    return $a($pos)
};

declare
    %test:assertTrue
function arr:deep-equal1() {
    deep-equal([1, <node/>, "a", ["b", "c"]], [1, <node/>, "a", ["b", "c"]])
};

declare
    %test:assertFalse
function arr:deep-equal2() {
    deep-equal([1, 2, "a", ["b", "c"]], [1, 2, "a", ["b", "a"]])
};

declare
    %test:assertEquals(2)
function arr:with-map1() {
    let $a := [ map { "a": 1, "b": 2 } ]
    return $a(1)("b")
};

declare
    %test:assertEquals(3)
function arr:with-map2() {
    let $a := map { "a": 1, "b": [2, 3, 4] }
    return $a("b")(2)
};

declare
    %test:assertEquals(5)
function arr:nested1() {
    let $a := [ [1, 2, 3], [4, 5, 6] ]
    return $a(2)(2)
};

declare
    %test:assertEquals(5)
function arr:nested2() {
    let $a := array { [1, 2, 3], [4, 5, 6] }
    return $a(2)(2)
};

declare
    %test:args(2)
function arr:size1() {
    array:size([
test
, 55])
};

declare
    %test:args(1)
function arr:size2() {
    array:size([[]])
};

declare
    %test:assertEquals(3, 4, 5)
function arr:append1() {
    array:append([1, 2], (3, 4, 5))(3)
};

declare
    %test:assertEmpty
function arr:append2() {
    array:append([1, 2], ())(3)
};

declare
    %test:assertEquals("a")
function arr:head1() {
    array:head(["a", "b"])
};

declare
    %test:assertEquals(2)
function arr:head2() {
    array:head([[1, 2], 3, 4, 5])(2)
};

declare
    %test:assertError("FOAY0001")
function arr:head-empty() {
    array:head([])
};

declare
    %test:assertEquals(2)
function arr:tail1() {
    array:tail([1, 2, 3])(1)
};

declare
    %test:assertEquals(2)
function arr:tail2() {
    array:tail([1, [2, 3]])(1)(1)
};

declare
    %test:assertEquals(0)
function arr:tail3() {
    array:size(array:tail([1]))
};

declare
    %test:assertError("FOAY0001")
function arr:tail-empty() {
    array:tail([])
};

declare
    %test:assertEquals(2, 3)
function arr:tail-on-array() {
    array:tail([1,[2,3]])?*?*
};

declare
    %test:args(2)
    %test:assertEquals("b", "c", "d")
    %test:args(5)
    %test:assertEmpty
function arr:subarray1($start as xs:int) {
    let $a := array:subarray(["a", "b", "c", "d"], $start)
    return
        $a?*
};

declare
    %test:args(5, 0)
    %test:assertEmpty
    %test:args(2, 0)
    %test:assertEmpty
    %test:args(2, 1)
    %test:assertEquals("b")
    %test:args(2, 2)
    %test:assertEquals("b", "c")
    %test:args(4, 1)
    %test:assertEquals("d")
    %test:args(1, 2)
    %test:assertEquals("a", "b")
    %test:args(1, 5)
    %test:assertError("FOAY0001")
    %test:args(0, 1)
    %test:assertError("FOAY0001")
    %test:args(1, "-1")
    %test:assertError("FOAY0002")
function arr:subarray2($start as xs:int, $length as xs:int) {
    let $a := array:subarray(["a", "b", "c", "d"], $start, $length)
    return
        $a?*
};

declare
    %test:args(1)
    %test:assertEquals("b", "c", "d")
    %test:args(2)
    %test:assertEquals("a", "c", "d")
    %test:args(4)
    %test:assertEquals("a", "b", "c")
    %test:args(0)
    %test:assertError("FOAY0001")
    %test:args(5)
    %test:assertError("FOAY0001")
function arr:remove1($pos as xs:int) {
    array:remove(["a", "b", "c", "d"], $pos)?*
};

declare
    %test:assertEmpty
function arr:remove2() {
    array:remove(["a"], 1)?*
};

declare
    %test:assertEquals("d", "c", "b", "a")
function arr:reverse1() {
    array:reverse(["a", "b", "c", "d"])?*
};

declare
    %test:assertEquals("c", "d", "a", "b")
function arr:reverse2() {
    array:reverse([("a", "b"), ("c", "d")])?*
};

declare
    %test:assertEquals("1", "2", "3", "4", "5")
function arr:reverse3() {
    array:reverse([(1 to 5)])?*
};

declare
    %test:assertEmpty
function arr:reverse4() {
    array:reverse([])?*
};

declare
    %test:assertEmpty
function arr:join1() {
    array:join(())?*
};

declare
    %test:assertEquals("a", "b", "c", "d")
function arr:join2() {
    array:join((["a", "b"], ["c", "d"], []))?*
};

declare
    %test:assertEquals(5)
function arr:join3() {
    array:size(array:join((["a", "b"], ["c", "d"], [["e", "f"]])))
};

declare
    %test:assertEquals("A", "B", "C", "D")
function arr:for-each1() {
    array:for-each(["a", "b", "c", "d"], upper-case#1)?*
};

declare
    %test:assertEquals("false", "false", "true", "true")
function arr:for-each2() {
    array:for-each(["a", "b", 1, 2], function($z) { $z instance of xs:integer })?*
};

declare
    %test:assertEquals("1", "2")
function arr:filter1() {
    array:filter(["a", "b", 1, 2], function($z) { $z instance of xs:integer })?*
};

declare
    %test:assertEquals("a", "b", 1)
function arr:filter2() {
    array:filter(["a", "b", "", 0, 1], boolean#1)?*
};

declare
    %test:assertEquals("the cat", "on the mat")
function arr:filter3() {
    array:filter(["the cat", "sat", "on the mat"], function($s) { count(tokenize($s, " ")) gt 1 })?*
};

declare
    %test:assertFalse
function arr:fold-left1() {
    array:fold-left([true(), true(), false()], true(), function($x, $y) { $x and $y })
};

declare
    %test:assertTrue
function arr:fold-left2() {
    array:fold-left([true(), true(), false()], false(), function($x, $y) { $x or $y })
};

declare
    %test:assertEquals(1)
function arr:fold-left3() {
    array:fold-left([], 1, function($x, $y) { $x + $y })
};

declare
    %test:assertEquals(8)
function arr:fold-left4() {
    array:fold-left(["abc", "def", "gh"], 0, function($x, $y) { $x + string-length($y) })
};

declare
    %test:assertEquals("abcdefgh")
function arr:fold-left5() {
    array:fold-left(["abc", "def", "gh"], "", function($x, $y) { $x || $y })
};

declare
    %test:assertEquals(1)
function arr:fold-left6() {
    array:fold-left([1, 2], (), function($x, $y) { [$x, $y] })?1?2
};

declare
    %test:assertFalse
function arr:fold-right1() {
    array:fold-right([true(), true(), false()], true(), function($x, $y) { $x and $y })
};

declare
    %test:assertTrue
function arr:fold-right2() {
    array:fold-right([true(), true(), false()], false(), function($x, $y) { $x or $y })
};

declare
    %test:assertEquals(2)
function arr:fold-right3() {
    array:fold-right([1, 2, 3], (), function($x, $y) { [$x, $y] })?2?1
};

declare
    %test:assertEquals(5, 4, 3, 2, 1)
function arr:fold-right4() {
    array:fold-right(
        array { 1 to 5 },
        (),
        function($a, $b) { $b, $a }
    )
};

declare
    %test:assertEquals("AB", "BC", "CD")
function arr:for-each-pair1() {
    let $a := ["A", "B", "C", "D"]
    return
        array:for-each-pair($a, array:tail($a), concat#2)?*
};

declare
    %test:assertEquals(5, 7, 9)
function arr:for-each-pair2() {
    array:for-each-pair(
        array { 1 to 3 },
        array { 4 to 6 },
        function($a, $b) { $a + $b }
    )?*
};

declare
    %test:assertEmpty
function arr:for-each-pair3() {
    array:for-each-pair(
        [],
        array { 4 to 6 },
        function($a, $b) { $a + $b }
    )?*
};

declare
    %test:assertEquals(1, 4, 6, 5, 3)
function arr:flatten1() {
    array:flatten([1, 4, 6, 5, 3])
};

declare
    %test:assertEquals(1, 2, 5, 10, 11, 12, 13)
function arr:flatten2() {
    array:flatten(([1, 2, 5], [[10, 11], 12], [], 13))
};

declare
    %test:assertEquals(1, 1, 0, 1, 1)
function arr:flatten3() {
    array:flatten((1, [(1, 0), (1, 1)]))
};

declare
    %test:assertEmpty
function arr:flatten4() {
    array:flatten(())
};

declare
    %test:assertEquals("a", "b", "x", "c", "d")
function arr:insert-before1() {
    array:insert-before(["a", "b", "c", "d"], 3, "x")?*
};

declare
    %test:assertEquals("x", "y")
function arr:insert-before2() {
    array:insert-before(["a", "b", "c", "d"], 3, ("x", "y"))?3
};

declare
    %test:assertEquals("a", "b", "c", "d", "x")
function arr:insert-before3() {
    array:insert-before(["a", "b", "c", "d"], 5, "x")?*
};

declare
    %test:assertEquals("array")
function arr:array-type1() {
    let $a := [1, 2]
    return
        typeswitch($a)
            case array(*) return
                "array"
            default return
                "no array"
};

declare
    %test:assertEquals("<t>test</t>")
function arr:apply-inline() {
    let $fn := function($a as xs:string, $b as xs:int, $c as element()) {
        $c
    }
    return
        apply($fn, ["a", 1, <t>test</t>])
};

declare
    %test:assertEquals("abc")
function arr:apply-internal() {
    apply(concat#3, ["a", "b", "c"])
};

declare
    %test:assertEquals("a", 1)
function arr:apply-param-array() {
    let $fn := function($a as array(*)) {
        $a?*
    }
    return
        apply($fn, [["a", 1]])
};

declare
    %test:assertEquals("1")
function arr:apply-param-map() {
    let $fn := function($m as map(*)) {
        $m?*
    }
    return
        apply($fn, [map { "key": 1 }])
};

declare
    %test:assertEquals(3)
function arr:apply-param-seq() {
    let $fn := function($s as item()*) {
        count($s)
    }
    return
        apply($fn, [(1, 2, 3)])
};

declare
    %test:assertEquals("HELLO WORLD")
function arr:apply-closure() {
    let $s := "Hello world"
    let $fn := function() {
        upper-case($s)
    }
    return
        apply($fn, [])
};

declare
    %test:args('"a"')
    %test:assertEquals("a")
    %test:args("2")
    %test:assertEquals(2)
    %test:args("true")
    %test:assertTrue
    %test:args("false")
    %test:assertFalse
    %test:args("null")
    %test:assertEmpty
    %test:args("[]")
    %test:assertXPath("array:size($result) = 0")
    %test:args('[1, "a"]')
    %test:assertXPath("$result?2 = 'a'")
    %test:args('[1, ["a", "b"]]')
    %test:assertXPath("$result?2?2 = 'b'")
    %test:args('[1, []]')
    %test:assertXPath("array:size($result?2) = 0")
    %test:args('[1, null]')
    %test:assertXPath("array:size($result) = 2")
    %test:args('{"key1": "val1", "key2": "val2"}')
    %test:assertXPath("$result?key2 = 'val2'")
    %test:args('{"key1": "val1", "key2": [1, 2]}')
    %test:assertXPath("$result?key2?2 = 2")
    %test:args('{"key1": null, "key2": "val2"}')
    %test:assertXPath("empty($result?key1)")
    %test:args('{key: "value"}')
    %test:assertError("FOJS0001")
    %test:args("{key: 'value'}")
    %test:assertError("FOJS0001")
    %test:args('{"k1": "v1", "k1": "v2"}')
    %test:assertXPath("$result?k1 = 'v2'")
function arr:parse-json($json as xs:string) {
    parse-json($json)
};

declare
    %test:args('{key: "value"}')
    %test:assertXPath("$result?key = 'value'")
    %test:args("{'key': 'value'}")
    %test:assertXPath("$result?key = 'value'")
function arr:parse-json-liberal($json as xs:string) {
    parse-json($json, map { "liberal": true() })
};

declare
    %test:args('{"k1": "v1", "k1": "v2"}', "reject")
    %test:assertError("FOJS0003")
    %test:args('{"k1": "v1", "k1": "v2"}', "use-first")
    %test:assertXPath("$result?k1 = 'v1'")
    %test:args('{"k1": "v1", "k1": "v2"}', "use-last")
    %test:assertXPath("$result?k1 = 'v2'")
function arr:parse-json-duplicates($json as xs:string, $duplicates as xs:string) {
    parse-json($json, map { "duplicates": $duplicates })
};

declare
    %test:assertXPath("$result?1?key2 = 'value2'")
function arr:json-doc-db() {
    json-doc("/db/array-test/test.json")
};

declare
    %test:assertError("FOJS0003")
function arr:json-doc-options() {
    json-doc("/db/array-test/test.json", map { "duplicates": "reject" })
};

(: Requires running server :)
declare
    %test:assertXPath("$result?1?key2 = 'value2'")
    %test:pending
function arr:json-doc-http() {
    json-doc("http://localhost:8080/exist/rest/db/array-test/test.json")
};

declare
    %test:assertError("FOUT1170")
function arr:json-doc-invalid() {
    json-doc("notfound.json")
};

declare
    %test:assertEquals('{"a1":22,"a2":["z","b","c"]}')
function arr:serialize() {
    let $json :=
        map {
            "a1": 22,
            "a2": [ "z", "b", "c" ]
        }
    let $serialized :=
        serialize($json, $arr:SERIALIZE_JSON)
    return
        $serialized
};

declare
    %test:assertTrue
function arr:serialize-roundtrip() {
    let $json :=
        map {
            "k1": 22,
            "k2": [ "z", "b", "c" ],
            "k3": map { "k4": array { 1 to 100 }, "k5": () }
        }
    let $serialized :=
        serialize($json, $arr:SERIALIZE_JSON)
    let $parsed := parse-json($serialized)
    return
        deep-equal($json, $parsed)
};

declare
    %test:assertEquals('{"xml":"

Test

"}')
function arr:serialize-node() {
    let $json :=
        map {
            "xml":

Test

        }
    return
        serialize($json, $arr:SERIALIZE_JSON)
};

declare
    %test:assertEquals('{"status":true}')
function arr:serialize-old-json-compat() {
    let $xmlJson := <result><status json:literal="true">true</status></result>
    return
        serialize($xmlJson, $arr:SERIALIZE_JSON)
};

declare
    %test:assertEquals('{ "status" : true }')
function arr:serialize-old-json-compat-indent() {
    let $xmlJson := <result><status json:literal="true">true</status></result>
    return
        serialize($xmlJson, $arr:SERIALIZE_JSON_INDENT)
};

declare
    %test:args(2)
    %test:assertTrue
    %test:args(3)
    %test:assertTrue
    %test:args(6)
    %test:assertTrue
    %test:args(7)
    %test:assertFalse
function arr:general-comparison1($val as xs:int) {
    [1, 2, 3, [5, 6]] = $val
};

declare
    %test:assertTrue
function arr:general-comparison2() {
    let $xml := <test>2</test>
    return
        $xml/a[. = [2, 3]]
};

declare
    %test:assertFalse
function arr:general-comparison3() {
    let $xml := <test>2</test>
    return
        $xml/a[. = [3, 4]]
};

declare
    %test:assertEquals("1")
function arr:general-comparison-range() {
    collection("/db/array-test")//a[. = [1, 2]]
};

declare
    %test:assertEquals("2")
function arr:general-comparison-range-new() {
    collection("/db/array-test")//b[. = [1, 2]]
};

declare
    %test:assertError
function arr:value-comparison() {
    let $xml := <test>3</test>
    return
        $xml/a[. eq [3, 4]]
};

declare
    %test:assertEquals(1)
function arr:cast-as() {
    array { 1 } cast as xs:double
};

declare
    %test:assertError
function arr:cast-as-invalid() {
    array { 1 to 3 } cast as xs:double
};

declare
    %test:assertEquals(1)
function arr:castable-as() {
    array { 1 } castable as xs:double
};

declare
    %test:assertError
function arr:castable-as-invalid() {
    array { 1 to 3 } castable as xs:double
};

declare
    %test:assertEquals("<test>
Hello world!
</test>")
function arr:enclosed-expr-element() {
    <test>
Hello {[world, "!"]}
</test>
};

declare
    %test:assertEquals("
Hello world !
")
function arr:element-computed() {
    element p {
        "Hello", ["world", "!"]
    }
};

declare
    %test:assertEquals('<test attr="1 2"/>')
function arr:enclosed-expr-attribute() {
    <test attr="{[1, 2]}"/>
};

declare
    %test:assertEquals('
')
function arr:attribute-computed() {
    element p {
        attribute attr { [1, 2] }
    }
};

declare
    %test:assertEquals('
Hello world
')
function arr:text-computed() {
    element p {
        text { ["Hello", "world"] }
    }
};

declare
    %test:assertEquals('

')
function arr:comment-computed() {
    element p {
        comment { ["Hello", "world"] }
    }
};

declare
    %test:assertEquals(1, 2, 3, 4)
function arr:fn-data() {
    data([1, 2, [3, 4]])
};

declare
    %test:assertEquals("a", "b")
function arr:nested-for-each() {
    array:for-each([["a","b"]],function($v){
        array:for-each($v,function($_){
            $_
        })
    })?*?*
};

declare
    %test:assertTrue
function arr:lookupWildcard() {
    let $expected := (1 to array:size($arr:primes)) ! $arr:primes(.)
    let $actual := $arr:primes?*
    return
        count($actual) eq count($expected)
        and
        (every $prime in $actual satisfies $prime = $expected)
};

(: Requires running server :)

declare
    %test:assertEquals("ok")
    %test:pending
function arr:restxq-serialize() {
    let $r := httpclient:get(
        xs:anyURI("http://localhost:8080/exist/restxq/arrays-test"), false(),
        <httpclient:headers>
            <httpclient:header name="Accept" value="application/json"/>
        </httpclient:headers>)
    let $json := parse-json(util:binary-to-string($r/httpclient:body))
    return
        $json?status
};

xquery version "3.1";

(:~
 : Tests for the array datatype and associated functions.
 :)
module namespace arr="http://exist-db.org/test/arrays";

declare namespace test="http://exist-db.org/xquery/xqsuite";
declare namespace output="http://www.w3.org/2010/xslt-xquery-serialization";
declare namespace json="http://www.json.org";

declare variable $arr:SERIALIZE_JSON :=
    <output:serialization-parameters>
        <output:method>json</output:method>
        <output:indent>no</output:indent>
    </output:serialization-parameters>;

declare variable $arr:SERIALIZE_JSON_INDENT :=
    <output:serialization-parameters>
        <output:method>json</output:method>
        <output:indent>yes</output:indent>
    </output:serialization-parameters>;

declare variable $arr:COLLECTION_CONF :=
    <collection xmlns="http://exist-db.org/collection-config/1.0">
        <index xmlns:xs="http://www.w3.org/2001/XMLSchema">
            <create qname="a" type="xs:int"/>
            <range>
                <create qname="b" type="xs:int"/>
            </range>
        </index>
        <triggers>
            <trigger class="org.exist.extensions.exquery.restxq.impl.RestXqTrigger"/>
        </triggers>
    </collection>;

declare variable $arr:XML_STORED :=
    <test>
        1
        2
    </test>;

declare variable $arr:RESTXQ_TEST :=
    'xquery version "3.1";

     module namespace rt="http://exist-db.org/restxq/rt";

     declare namespace rest="http://exquery.org/ns/restxq";
     declare namespace output="http://www.w3.org/2010/xslt-xquery-serialization";

     declare
         %rest:GET
         %rest:path("/arrays-test")
         %output:method("json")
         %rest:produces("application/json")
     function rt:json-test() {
         map {
             "status": "ok",
             "counters": array { 1 to 10 }
         }
     };';

declare variable $arr:primes := [2, 3, 5, 7, 11, 13, 17, 19];

declare
    %test:setUp
function arr:setup() {
    let $json := '[{"key1": "value1", "key2": "value2", "key1": "value3"}]'
    let $coll := xmldb:create-collection("/db", "array-test")
    let $confColl := xmldb:create-collection("/db/system/config/db", "array-test")
    return (
        xmldb:store($confColl, "collection.xconf", $arr:COLLECTION_CONF),
        xmldb:store($coll, "test.json", $json),
        xmldb:store($coll, "test.xml", $arr:XML_STORED),
        xmldb:store($coll, "test.xql", $arr:RESTXQ_TEST),
        sm:chmod(xs:anyURI($coll || "/test.xql"), "r-xr-xr-x")
    )
};

declare
    %test:tearDown
function arr:cleanup() {
    xmldb:remove("/db/array-test"),
    xmldb:remove("/db/system/config/db/array-test")
};

declare
    %test:args(1)
    %test:assertEquals(13)
    %test:args(3)
    %test:assertEquals(14)
function arr:function-item($pos as xs:int) {
    [13, 10, 14]($pos)
};

declare
    %test:args(1)
    %test:assertEquals(13)
    %test:args(3)
    %test:assertEquals(14)
function arr:function-item2($pos as xs:int) {
    let $a := [13, 10, 14]
    return
        $a($pos)
};

declare
    %test:args(1)
    %test:assertEquals(13)
    %test:args(3)
    %test:assertEquals(14)
function arr:function-item3($pos as xs:int) {
    let $a := [13, 10, 14]
    let $f := function($array as function(*), $position as xs:int) {
        $array($position)
    }
    return
        $f($a, $pos)
};

declare
    %test:assertError("FOAY0001")
function arr:function-item-out-of-bounds() {
    let $a := [13, 10, 14]
    return
        $a(22)
};

declare
    %test:assertError("err:XPTY0004")
function arr:function-item-invalid() {
    let $a := [13, 10, 14]
    return
        $a("x")
};

declare
    %test:assertError("FOAY0001")
function arr:get-item-out-of-bounds-positive() {
    let $a := [13, 10, 14]
    return
        array:get($a, 22)
};

declare
    %test:assertError("FOAY0001")
function arr:get-item-out-of-bounds-zero() {
    let $a := [13, 10, 14]
    return
        array:get($a, 0)
};

declare
    %test:assertError("FOAY0001")
function arr:get-item-out-of-bounds-negative() {
    let $a := [13, 10, 14]
    return
        array:get($a, -1)
};

declare
    %test:args(1)
    %test:assertEmpty
    %test:args(2)
    %test:assertEquals(27, 17, 0)
function arr:square-constructor1($pos as xs:int) {
    let $a := [(), (27, 17, 0)]
    return $a($pos)
};

declare
    %test:args(1)
    %test:assertEquals("
test
")
    %test:args(2)
    %test:assertEquals(55)
function arr:square-constructor2($pos as xs:int) {
    let $a := [
test
, 55]
    return $a($pos)
};

declare
    %test:assertEquals(0)
function arr:square-constructor3() {
    let $a := []
    return array:size($a)
};

declare
    %test:args(1)
    %test:assertEquals(27)
    %test:args(2)
    %test:assertEquals(17)
function arr:curly-constructor1($pos as xs:int) {
    let $x := (27, 17, 0)
    let $a := array { $x }
    return $a($pos)
};

declare
    %test:args(1)
    %test:assertEquals(27)
    %test:args(2)
    %test:assertEquals(17)
function arr:curly-constructor2($pos as xs:int) {
    let $a := array { (), (27, 17, 0) }
    return $a($pos)
};

declare
    %test:assertTrue
function arr:deep-equal1() {
    deep-equal([1, <node/>, "a", ["b", "c"]], [1, <node/>, "a", ["b", "c"]])
};

declare
    %test:assertFalse
function arr:deep-equal2() {
    deep-equal([1, 2, "a", ["b", "c"]], [1, 2, "a", ["b", "a"]])
};

declare
    %test:assertEquals(2)
function arr:with-map1() {
    let $a := [ map { "a": 1, "b": 2 } ]
    return $a(1)("b")
};

declare
    %test:assertEquals(3)
function arr:with-map2() {
    let $a := map { "a": 1, "b": [2, 3, 4] }
    return $a("b")(2)
};

declare
    %test:assertEquals(5)
function arr:nested1() {
    let $a := [ [1, 2, 3], [4, 5, 6] ]
    return $a(2)(2)
};

declare
    %test:assertEquals(5)
function arr:nested2() {
    let $a := array { [1, 2, 3], [4, 5, 6] }
    return $a(2)(2)
};

declare
    %test:args(2)
function arr:size1() {
    array:size([
test
, 55])
};

declare
    %test:args(1)
function arr:size2() {
    array:size([[]])
};

declare
    %test:assertEquals(3, 4, 5)
function arr:append1() {
    array:append([1, 2], (3, 4, 5))(3)
};

declare
    %test:assertEmpty
function arr:append2() {
    array:append([1, 2], ())(3)
};

declare
    %test:assertEquals("a")
function arr:head1() {
    array:head(["a", "b"])
};

declare
    %test:assertEquals(2)
function arr:head2() {
    array:head([[1, 2], 3, 4, 5])(2)
};

declare
    %test:assertError("FOAY0001")
function arr:head-empty() {
    array:head([])
};

declare
    %test:assertEquals(2)
function arr:tail1() {
    array:tail([1, 2, 3])(1)
};

declare
    %test:assertEquals(2)
function arr:tail2() {
    array:tail([1, [2, 3]])(1)(1)
};

declare
    %test:assertEquals(0)
function arr:tail3() {
    array:size(array:tail([1]))
};

declare
    %test:assertError("FOAY0001")
function arr:tail-empty() {
    array:tail([])
};

declare
    %test:assertEquals(2, 3)
function arr:tail-on-array() {
    array:tail([1,[2,3]])?*?*
};

declare
    %test:args(2)
    %test:assertEquals("b", "c", "d")
    %test:args(5)
    %test:assertEmpty
function arr:subarray1($start as xs:int) {
    let $a := array:subarray(["a", "b", "c", "d"], $start)
    return
        $a?*
};

declare
    %test:args(5, 0)
    %test:assertEmpty
    %test:args(2, 0)
    %test:assertEmpty
    %test:args(2, 1)
    %test:assertEquals("b")
    %test:args(2, 2)
    %test:assertEquals("b", "c")
    %test:args(4, 1)
    %test:assertEquals("d")
    %test:args(1, 2)
    %test:assertEquals("a", "b")
    %test:args(1, 5)
    %test:assertError("FOAY0001")
    %test:args(0, 1)
    %test:assertError("FOAY0001")
    %test:args(1, "-1")
    %test:assertError("FOAY0002")
function arr:subarray2($start as xs:int, $length as xs:int) {
    let $a := array:subarray(["a", "b", "c", "d"], $start, $length)
    return
        $a?*
};

declare
    %test:args(1)
    %test:assertEquals("b", "c", "d")
    %test:args(2)
    %test:assertEquals("a", "c", "d")
    %test:args(4)
    %test:assertEquals("a", "b", "c")
    %test:args(0)
    %test:assertError("FOAY0001")
    %test:args(5)
    %test:assertError("FOAY0001")
function arr:remove1($pos as xs:int) {
    array:remove(["a", "b", "c", "d"], $pos)?*
};

declare
    %test:assertEmpty
function arr:remove2() {
    array:remove(["a"], 1)?*
};

declare
    %test:assertEquals("d", "c", "b", "a")
function arr:reverse1() {
    array:reverse(["a", "b", "c", "d"])?*
};

declare
    %test:assertEquals("c", "d", "a", "b")
function arr:reverse2() {
    array:reverse([("a", "b"), ("c", "d")])?*
};

declare
    %test:assertEquals("1", "2", "3", "4", "5")
function arr:reverse3() {
    array:reverse([(1 to 5)])?*
};

declare
    %test:assertEmpty
function arr:reverse4() {
    array:reverse([])?*
};

declare
    %test:assertEmpty
function arr:join1() {
    array:join(())?*
};

declare
    %test:assertEquals("a", "b", "c", "d")
function arr:join2() {
    array:join((["a", "b"], ["c", "d"], []))?*
};

declare
    %test:assertEquals(5)
function arr:join3() {
    array:size(array:join((["a", "b"], ["c", "d"], [["e", "f"]])))
};

declare
    %test:assertEquals("A", "B", "C", "D")
function arr:for-each1() {
    array:for-each(["a", "b", "c", "d"], upper-case#1)?*
};

declare
    %test:assertEquals("false", "false", "true", "true")
function arr:for-each2() {
    array:for-each(["a", "b", 1, 2], function($z) { $z instance of xs:integer })?*
};

declare
    %test:assertEquals("1", "2")
function arr:filter1() {
    array:filter(["a", "b", 1, 2], function($z) { $z instance of xs:integer })?*
};

declare
    %test:assertEquals("a", "b", 1)
function arr:filter2() {
    array:filter(["a", "b", "", 0, 1], boolean#1)?*
};

declare
    %test:assertEquals("the cat", "on the mat")
function arr:filter3() {
    array:filter(["the cat", "sat", "on the mat"], function($s) { count(tokenize($s, " ")) gt 1 })?*
};

declare
    %test:assertFalse
function arr:fold-left1() {
    array:fold-left([true(), true(), false()], true(), function($x, $y) { $x and $y })
};

declare
    %test:assertTrue
function arr:fold-left2() {
    array:fold-left([true(), true(), false()], false(), function($x, $y) { $x or $y })
};

declare
    %test:assertEquals(1)
function arr:fold-left3() {
    array:fold-left([], 1, function($x, $y) { $x + $y })
};

declare
    %test:assertEquals(8)
function arr:fold-left4() {
    array:fold-left(["abc", "def", "gh"], 0, function($x, $y) { $x + string-length($y) })
};

declare
    %test:assertEquals("abcdefgh")
function arr:fold-left5() {
    array:fold-left(["abc", "def", "gh"], "", function($x, $y) { $x || $y })
};

declare
    %test:assertEquals(1)
function arr:fold-left6() {
    array:fold-left([1, 2], (), function($x, $y) { [$x, $y] })?1?2
};

declare
    %test:assertFalse
function arr:fold-right1() {
    array:fold-right([true(), true(), false()], true(), function($x, $y) { $x and $y })
};

declare
    %test:assertTrue
function arr:fold-right2() {
    array:fold-right([true(), true(), false()], false(), function($x, $y) { $x or $y })
};

declare
    %test:assertEquals(2)
function arr:fold-right3() {
    array:fold-right([1, 2, 3], (), function($x, $y) { [$x, $y] })?2?1
};

declare
    %test:assertEquals(5, 4, 3, 2, 1)
function arr:fold-right4() {
    array:fold-right(
        array { 1 to 5 },
        (),
        function($a, $b) { $b, $a }
    )
};

declare
    %test:assertEquals("AB", "BC", "CD")
function arr:for-each-pair1() {
    let $a := ["A", "B", "C", "D"]
    return
        array:for-each-pair($a, array:tail($a), concat#2)?*
};

declare
    %test:assertEquals(5, 7, 9)
function arr:for-each-pair2() {
    array:for-each-pair(
        array { 1 to 3 },
        array { 4 to 6 },
        function($a, $b) { $a + $b }
    )?*
};

declare
    %test:assertEmpty
function arr:for-each-pair3() {
    array:for-each-pair(
        [],
        array { 4 to 6 },
        function($a, $b) { $a + $b }
    )?*
};

declare
    %test:assertEquals(1, 4, 6, 5, 3)
function arr:flatten1() {
    array:flatten([1, 4, 6, 5, 3])
};

declare
    %test:assertEquals(1, 2, 5, 10, 11, 12, 13)
function arr:flatten2() {
    array:flatten(([1, 2, 5], [[10, 11], 12], [], 13))
};

declare
    %test:assertEquals(1, 1, 0, 1, 1)
function arr:flatten3() {
    array:flatten((1, [(1, 0), (1, 1)]))
};

declare
    %test:assertEmpty
function arr:flatten4() {
    array:flatten(())
};

declare
    %test:assertEquals("a", "b", "x", "c", "d")
function arr:insert-before1() {
    array:insert-before(["a", "b", "c", "d"], 3, "x")?*
};

declare
    %test:assertEquals("x", "y")
function arr:insert-before2() {
    array:insert-before(["a", "b", "c", "d"], 3, ("x", "y"))?3
};

declare
    %test:assertEquals("a", "b", "c", "d", "x")
function arr:insert-before3() {
    array:insert-before(["a", "b", "c", "d"], 5, "x")?*
};

declare
    %test:assertEquals("array")
function arr:array-type1() {
    let $a := [1, 2]
    return
        typeswitch($a)
            case array(*) return
                "array"
            default return
                "no array"
};

declare
    %test:assertEquals("<t>test</t>")
function arr:apply-inline() {
    let $fn := function($a as xs:string, $b as xs:int, $c as element()) {
        $c
    }
    return
        apply($fn, ["a", 1, <t>test</t>])
};

declare
    %test:assertEquals("abc")
function arr:apply-internal() {
    apply(concat#3, ["a", "b", "c"])
};

declare
    %test:assertEquals("a", 1)
function arr:apply-param-array() {
    let $fn := function($a as array(*)) {
        $a?*
    }
    return
        apply($fn, [["a", 1]])
};

declare
    %test:assertEquals("1")
function arr:apply-param-map() {
    let $fn := function($m as map(*)) {
        $m?*
    }
    return
        apply($fn, [map { "key": 1 }])
};

declare
    %test:assertEquals(3)
function arr:apply-param-seq() {
    let $fn := function($s as item()*) {
        count($s)
    }
    return
        apply($fn, [(1, 2, 3)])
};

declare
    %test:assertEquals("HELLO WORLD")
function arr:apply-closure() {
    let $s := "Hello world"
    let $fn := function() {
        upper-case($s)
    }
    return
        apply($fn, [])
};

declare
    %test:args('"a"')
    %test:assertEquals("a")
    %test:args("2")
    %test:assertEquals(2)
    %test:args("true")
    %test:assertTrue
    %test:args("false")
    %test:assertFalse
    %test:args("null")
    %test:assertEmpty
    %test:args("[]")
    %test:assertXPath("array:size($result) = 0")
    %test:args('[1, "a"]')
    %test:assertXPath("$result?2 = 'a'")
    %test:args('[1, ["a", "b"]]')
    %test:assertXPath("$result?2?2 = 'b'")
    %test:args('[1, []]')
    %test:assertXPath("array:size($result?2) = 0")
    %test:args('[1, null]')
    %test:assertXPath("array:size($result) = 2")
    %test:args('{"key1": "val1", "key2": "val2"}')
    %test:assertXPath("$result?key2 = 'val2'")
    %test:args('{"key1": "val1", "key2": [1, 2]}')
    %test:assertXPath("$result?key2?2 = 2")
    %test:args('{"key1": null, "key2": "val2"}')
    %test:assertXPath("empty($result?key1)")
    %test:args('{key: "value"}')
    %test:assertError("FOJS0001")
    %test:args("{key: 'value'}")
    %test:assertError("FOJS0001")
    %test:args('{"k1": "v1", "k1": "v2"}')
    %test:assertXPath("$result?k1 = 'v2'")
function arr:parse-json($json as xs:string) {
    parse-json($json)
};

declare
    %test:args('{key: "value"}')
    %test:assertXPath("$result?key = 'value'")
    %test:args("{'key': 'value'}")
    %test:assertXPath("$result?key = 'value'")
function arr:parse-json-liberal($json as xs:string) {
    parse-json($json, map { "liberal": true() })
};

declare
    %test:args('{"k1": "v1", "k1": "v2"}', "reject")
    %test:assertError("FOJS0003")
    %test:args('{"k1": "v1", "k1": "v2"}', "use-first")
    %test:assertXPath("$result?k1 = 'v1'")
    %test:args('{"k1": "v1", "k1": "v2"}', "use-last")
    %test:assertXPath("$result?k1 = 'v2'")
function arr:parse-json-duplicates($json as xs:string, $duplicates as xs:string) {
    parse-json($json, map { "duplicates": $duplicates })
};

declare
    %test:assertXPath("$result?1?key2 = 'value2'")
function arr:json-doc-db() {
    json-doc("/db/array-test/test.json")
};

declare
    %test:assertError("FOJS0003")
function arr:json-doc-options() {
    json-doc("/db/array-test/test.json", map { "duplicates": "reject" })
};

(: Requires running server :)
declare
    %test:assertXPath("$result?1?key2 = 'value2'")
    %test:pending
function arr:json-doc-http() {
    json-doc("http://localhost:8080/exist/rest/db/array-test/test.json")
};

declare
    %test:assertError("FOUT1170")
function arr:json-doc-invalid() {
    json-doc("notfound.json")
};

declare
    %test:assertEquals('{"a1":22,"a2":["z","b","c"]}')
function arr:serialize() {
    let $json :=
        map {
            "a1": 22,
            "a2": [ "z", "b", "c" ]
        }
    let $serialized :=
        serialize($json, $arr:SERIALIZE_JSON)
    return
        $serialized
};

declare
    %test:assertTrue
function arr:serialize-roundtrip() {
    let $json :=
        map {
            "k1": 22,
            "k2": [ "z", "b", "c" ],
            "k3": map { "k4": array { 1 to 100 }, "k5": () }
        }
    let $serialized :=
        serialize($json, $arr:SERIALIZE_JSON)
    let $parsed := parse-json($serialized)
    return
        deep-equal($json, $parsed)
};

declare
    %test:assertEquals('{"xml":"

Test

"}')
function arr:serialize-node() {
    let $json :=
        map {
            "xml":

Test

        }
    return
        serialize($json, $arr:SERIALIZE_JSON)
};

declare
    %test:assertEquals('{"status":true}')
function arr:serialize-old-json-compat() {
    let $xmlJson := <result><status json:literal="true">true</status></result>
    return
        serialize($xmlJson, $arr:SERIALIZE_JSON)
};

declare
    %test:assertEquals('{ "status" : true }')
function arr:serialize-old-json-compat-indent() {
    let $xmlJson := <result><status json:literal="true">true</status></result>
    return
        serialize($xmlJson, $arr:SERIALIZE_JSON_INDENT)
};

declare
    %test:args(2)
    %test:assertTrue
    %test:args(3)
    %test:assertTrue
    %test:args(6)
    %test:assertTrue
    %test:args(7)
    %test:assertFalse
function arr:general-comparison1($val as xs:int) {
    [1, 2, 3, [5, 6]] = $val
};

declare
    %test:assertTrue
function arr:general-comparison2() {
    let $xml := <test>2</test>
    return
        $xml/a[. = [2, 3]]
};

declare
    %test:assertFalse
function arr:general-comparison3() {
    let $xml := <test>2</test>
    return
        $xml/a[. = [3, 4]]
};

declare
    %test:assertEquals("1")
function arr:general-comparison-range() {
    collection("/db/array-test")//a[. = [1, 2]]
};

declare
    %test:assertEquals("2")
function arr:general-comparison-range-new() {
    collection("/db/array-test")//b[. = [1, 2]]
};

declare
    %test:assertError
function arr:value-comparison() {
    let $xml := <test>3</test>
    return
        $xml/a[. eq [3, 4]]
};

declare
    %test:assertEquals(1)
function arr:cast-as() {
    array { 1 } cast as xs:double
};

declare
    %test:assertError
function arr:cast-as-invalid() {
    array { 1 to 3 } cast as xs:double
};

declare
    %test:assertEquals(1)
function arr:castable-as() {
    array { 1 } castable as xs:double
};

declare
    %test:assertError
function arr:castable-as-invalid() {
    array { 1 to 3 } castable as xs:double
};

declare
    %test:assertEquals("<test>
Hello world!
</test>")
function arr:enclosed-expr-element() {
    <test>
Hello {[world, "!"]}
</test>
};

declare
    %test:assertEquals("
Hello world !
")
function arr:element-computed() {
    element p {
        "Hello", ["world", "!"]
    }
};

declare
    %test:assertEquals('<test attr="1 2"/>')
function arr:enclosed-expr-attribute() {
    <test attr="{[1, 2]}"/>
};

declare
    %test:assertEquals('
')
function arr:attribute-computed() {
    element p {
        attribute attr { [1, 2] }
    }
};

declare
    %test:assertEquals('
Hello world
')
function arr:text-computed() {
    element p {
        text { ["Hello", "world"] }
    }
};

declare
    %test:assertEquals('

')
function arr:comment-computed() {
    element p {
        comment { ["Hello", "world"] }
    }
};

declare
    %test:assertEquals(1, 2, 3, 4)
function arr:fn-data() {
    data([1, 2, [3, 4]])
};

declare
    %test:assertEquals("a", "b")
function arr:nested-for-each() {
    array:for-each([["a","b"]],function($v){
        array:for-each($v,function($_){
            $_
        })
    })?*?*
};

declare
    %test:assertTrue
function arr:lookupWildcard() {
    let $expected := (1 to array:size($arr:primes)) ! $arr:primes(.)
    let $actual := $arr:primes?*
    return
        count($actual) eq count($expected)
        and
        (every $prime in $actual satisfies $prime = $expected)
};

(: Requires running server :)

declare
    %test:assertEquals("ok")
    %test:pending
function arr:restxq-serialize() {
    let $r := httpclient:get(
        xs:anyURI("http://localhost:8080/exist/restxq/arrays-test"), false(),
        <httpclient:headers>
            <httpclient:header name="Accept" value="application/json"/>
        </httpclient:headers>)
    let $json := parse-json(util:binary-to-string($r/httpclient:body))
    return
        $json?status
};


Bug fix for when document did not exist

Bug fix for when document did not exist

xquery version "1.0" encoding "UTF-8";

declare variable $data-collection as xs:anyURI := xs:anyURI('/db/apps/exist-book/data');
declare variable $update-resource as xs:string := 'update-resource.xml';

declare function local:make-sure-update-resource-exists() as xs:string?
{
    if($update-resource = xmldb:get-child-resources($data-collection))then
        () (: Resource exists... :)
    else
        (: Resource does not exist, create... :)
        xmldb:store($data-collection, $update-resource, <UpdateResource created="{current-dateTime()}"/>)
};

let $full-uri as xs:string := concat($data-collection, '/', $update-resource)
return
    <UpdateResult document="{$full-uri}" created="{local:make-sure-update-resource-exists()}">
    {
        let $root-elm as element() := doc($full-uri)/*
        return (
          update insert attribute changed {current-dateTime()} into $root-elm,
          update insert <NewElement/> into $root-elm
        )
    }
        Changed: {$full-uri}
    </UpdateResult>

xquery version "1.0" encoding "UTF-8";

declare variable $data-collection as xs:anyURI := xs:anyURI('/db/apps/exist-book/data');
declare variable $update-resource as xs:string := 'update-resource.xml';

declare function local:make-sure-update-resource-exists() as xs:string?
{
    if($update-resource = xmldb:get-child-resources($data-collection))then
        () (: Resource exists... :)
    else
        (: Resource does not exist, create... :)
        xmldb:store($data-collection, $update-resource, <UpdateResource created="{current-dateTime()}"/>)
};

let $full-uri as xs:string := concat($data-collection, '/', $update-resource)
let $root-elm as element() := doc($full-uri)/*
return
    <UpdateResult document="{$full-uri}" created="{local:make-sure-update-resource-exists()}">
    {
        update insert attribute changed {current-dateTime()} into $root-elm,
        update insert <NewElement/> into $root-elm
    }
        Changed: {$full-uri}
    </UpdateResult>


example invoking changed signature

example invoking changed signature

git-svn-id: 2087087167f935058d19856144d26af79f295c86@129433 62cac252-8da6-4816-9e9d-6dc37b19578c

xquery version "1.0-ml";

(: Copyright 2011-2012 MarkLogic Corporation.  All Rights Reserved. :)

module namespace searchcollect = "http://marklogic.com/rest-api/resource/searchcollect";

(: WARNING:
    The search model library may change in a future release without notice.
    Do not call the functions of the search model library in your own code.
    :)
import module namespace searchmodq = "http://marklogic.com/rest-api/models/search-model-query"
    at "/MarkLogic/rest-api/models/search-model-query.xqy";

declare namespace search = "http://marklogic.com/appservices/search";

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

declare function searchcollect:get(
    $context as map:map,
    $params  as map:map
) as document-node()*
{
    let $headers :=
        let $map := map:map()
        return (
            map:put($map, "accept", "application/xml"),
            $map
            )
    let $results := (
        searchcollect:prepare-params($params),

        if (exists(map:get($params,"q")))
        then searchmodq:search-get($headers,$params,())
        else if (
            exists(map:get($params,"value")) and
            (exists(map:get($params,"key")) or exists(map:get($params,"element")))
            )
        then searchmodq:keyvalue-get($headers,$params,())
        else error((),"REST-INVALIDPARAM",
            "no query parameters for collecting documents"
            )
        )
    return searchcollect:results($context,$results)
};

declare function searchcollect:post(
    $context as map:map,
    $params  as map:map,
    $input   as document-node()*
) as document-node()*
{
    if (empty($input))
    then error((),"RESTAPI-INVALIDCONTENT","empty input for collecting documents")
    else
        let $headers :=
            let $map := map:map()
            return (
                map:put($map, "accept", "application/xml"),
                $map
                )
        return (
            searchcollect:prepare-params($params),

            searchcollect:results(
                $context,
                searchmodq:search-post($headers,$params,(),$input)
                )
            )
};

declare private function searchcollect:prepare-params(
    $params as map:map
) as empty-sequence()
{
    let $views      := map:get($params,"view")
    let $start      := map:get($params,"start")
    let $pageLength := map:get($params,"pageLength")
    return (
        if ($views = "results") then ()
        else map:put($params,"view",($views,"results")),

        if (empty($start))
        then map:put($params,"start",xs:unsignedLong(1))
        else map:put($params,"start",xs:unsignedLong($start)),

        if (empty($pageLength))
        then map:put($params,"pageLength",xs:unsignedLong(10))
        else map:put($params,"pageLength",xs:unsignedLong($pageLength))
        )
};

declare private function searchcollect:results(
    $context  as map:map,
    $response as element(search:response)?
) as document-node()*
{
    if (empty($response)) then ()
    else
        let $results := $response/search:result/@uri/string(.)
        return (
(: TODO: property or content :)
            map:put($context, "output-boundary",
                "document-collect-"||xdmp:random()),
            map:put($context, "output-types",
                ("application/xml", $results ! (
                    let $type := xdmp:uri-content-type(.)
                    return
                        if ($type eq "text/xml")
                        then "application/xml"
                        else $type))),
            document {$response},
            $results ! doc(.)
            )
};

xquery version "1.0-ml";

(: Copyright 2011-2012 MarkLogic Corporation.  All Rights Reserved. :)

module namespace searchcollect = "http://marklogic.com/rest-api/resource/searchcollect";

(: WARNING:
    The search model library may change in a future release without notice.
    Do not call the functions of the search model library in your own code.
    :)
import module namespace searchmodq = "http://marklogic.com/rest-api/models/search-model-query"
    at "/MarkLogic/rest-api/models/search-model-query.xqy";

declare namespace search = "http://marklogic.com/appservices/search";

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

declare function searchcollect:get(
    $context as map:map,
    $params  as map:map
) as document-node()*
{
    let $headers :=
        let $map := map:map()
        return (
            map:put($map, "accept", "application/xml"),
            $map
            )
    let $results := (
        searchcollect:prepare-params($params),

        if (exists(map:get($params,"q")))
        then searchmodq:search-get($headers, $params)
        else if (
            exists(map:get($params,"value")) and
            (exists(map:get($params,"key")) or exists(map:get($params,"element")))
            )
        then searchmodq:keyvalue-get($headers, $params)
        else error((),"REST-INVALIDPARAM",
            "no query parameters for collecting documents"
            )
        )
    return searchcollect:results($context,$results)
};

declare function searchcollect:post(
    $context as map:map,
    $params  as map:map,
    $input   as document-node()*
) as document-node()*
{
    if (empty($input))
    then error((),"RESTAPI-INVALIDCONTENT","empty input for collecting documents")
    else
        let $headers :=
            let $map := map:map()
            return (
                map:put($map, "accept", "application/xml"),
                $map
                )
        return (
            searchcollect:prepare-params($params),

            searchcollect:results(
                $context,
                searchmodq:search-post($headers,$params,$input)
                )
            )
};

declare private function searchcollect:prepare-params(
    $params as map:map
) as empty-sequence()
{
    let $views      := map:get($params,"view")
    let $start      := map:get($params,"start")
    let $pageLength := map:get($params,"pageLength")
    return (
        if ($views = "results") then ()
        else map:put($params,"view",($views,"results")),

        if (empty($start))
        then map:put($params,"start",xs:unsignedLong(1))
        else map:put($params,"start",xs:unsignedLong($start)),

        if (empty($pageLength))
        then map:put($params,"pageLength",xs:unsignedLong(10))
        else map:put($params,"pageLength",xs:unsignedLong($pageLength))
        )
};

declare private function searchcollect:results(
    $context  as map:map,
    $response as element(search:response)?
) as document-node()*
{
    if (empty($response)) then ()
    else
        let $results := $response/search:result/@uri/string(.)
        return (
(: TODO: property or content :)
            map:put($context, "output-boundary",
                "document-collect-"||xdmp:random()),
            map:put($context, "output-types",
                ("application/xml", $results ! (
                    let $type := xdmp:uri-content-type(.)
                    return
                        if ($type eq "text/xml")
                        then "application/xml"
                        else $type))),
            document {$response},
            $results ! doc(.)
            )
};


spot edit to date arithmetic example

spot edit to date arithmetic example

xquery version "3.1";
declare namespace ebb="http://newtfire.org";
declare variable $rocketColl := collection('/db/rocket/');
(: ebb: This script introduces you to user-defined functions in XQuery.
These can be useful for taking values from your XQuery variables and performing a conversion, as we're doing here.
Since the Rocket Launches project has multiple attributes encoding launch dates and landing dates in the same xs:dateTime format,
and since they work with the xs:duration datatype too, for coding how long a mission lasted,
we can work with these data to do "date arithmetic" to make simple graphs and charts if we can convert it to a simple decimal notation.
Let's start reading this by skipping past the section I've marked off with asterisks as USER-DEFINED FUNCTIONS, and come back to it :)

(: **************** USER-DEFINED FUNCTIONS **************************:)
(: CONVERT DATETIME to DECIMAL :)
(: ebb :This user-defined function will unpack the date components from an input xs:dateTime datatype.
We will first extract the year from the datatype with year-from-dateTime(),
and then use format-dateTime() to return a 'picture string' that will give us the date's numerical position in the year.
We then divide that date number by 365 (since most years have 365 days).
This will give us a decimal format we can use in making charts and graphs. :)
declare function ebb:dateDecimalConverter($dT as xs:dateTime)
as xs:decimal?
{
let $year := year-from-dateTime($dT) ! xs:integer(.)
let $dayInYear := format-dateTime($dT, '[d]') ! xs:integer(.)
let $decimalDay := $dayInYear div 365
return $year + $decimalDay
};
(: CONVERT DURATION TO DECIMAL :)
(: ebb: The next user-defined function will convert the xs:duration datatype into a decimal value based on number of days.
 : So if we input a duration indicating 1 day, 6 hours, and 0 minutes, we should return 1.25 from this function.
 : Here's what we're calculating: There are 24 hours in a day. (Divide the H portion by 24) and add it to the days.
 : There are 60 minutes in an hour. (Divide the M portion by 60 * 24) and add it to hours.
 : There are 60 seconds in a minute (Divide the S portion by 60 * 60 * 24) and add it to minutes and hours
 : :)
declare function ebb:durationConverter($d as xs:integer, $h as xs:integer, $m as xs:integer, $s as xs:integer?)
as xs:decimal?
{
let $TDec := $h div 24 + $m div (60 * 24) + $s div (60 * 60 * 24)
return $d + $TDec
};
(: *******************END USER-DEFINED FUNCTIONS ********************** :)

let $launchDateTimes := $rocketColl//launch/@sDateTime
for $l in $launchDateTimes
(: To do date arithmetic, take a look at these functions: https://www.w3.org/TR/xpath-functions-31/#dates-times
 : We'll write a user-defined function to convert this datatype into a decimal notation. :)
let $lDec := ebb:dateDecimalConverter($l)
let $m := $rocketColl//launch[@sDateTime = $l]/preceding-sibling::sts
let $mID := $m  ! tokenize(., ':')[1]

let $duration := $m/following-sibling::duration/@time
(: ebb: To do duration arithmetic, start by looking at the functions here: https://www.w3.org/TR/xpath-functions-31/#durations
 : Let's try representing durations in terms of days with a decimal.
 : We'll write a user-defined function to convert hours, minutes, and seconds into a fraction of the day. :)
let $durDays := days-from-duration($duration)
let $durHours := hours-from-duration($duration)
let $durMins := minutes-from-duration($duration)
let $durSecs := seconds-from-duration($duration)
(: Now in line 43, we send our variables to our user-defined function for turning date datatypes into decimal values. :)
let $durDayDec := ebb:durationConverter($durDays, $durHours, $durMins, $durSecs)

order by $lDec
return concat('Launch Date: ', $l, ', mission: ', $mID, ': This Launch Decimal Date: ', $lDec, ': Duration: ', $duration, ': Decimal Notation:', $durDayDec)

xquery version "3.1";
declare namespace ebb="http://newtfire.org";
declare variable $rocketColl := collection('/db/rocket/');
(: ebb: This XQuery introduces you to user-defined functions in XQuery.
These can be useful for taking values from your XQuery variables and performing a conversion, as we're doing here.
Since the Rocket Launches project has multiple attributes encoding launch dates and landing dates in the same xs:dateTime format,
and since they work with the xs:duration datatype too, for coding how long a mission lasted,
we can work with these data to do "date arithmetic" to make simple graphs and charts if we can convert it to a simple decimal notation.
Let's start reading this by skipping past the section I've marked off with asterisks as USER-DEFINED FUNCTIONS, and come back to it :)

(: **************** USER-DEFINED FUNCTIONS **************************:)
(: CONVERT DATETIME to DECIMAL :)
(: ebb :This user-defined function will unpack the date components from an input xs:dateTime datatype.
We will first extract the year from the datatype with year-from-dateTime(),
and then use format-dateTime() to return a 'picture string' that will give us the date's numerical position in the year.
We then divide that date number by 365 (since most years have 365 days).
This will give us a decimal format we can use in making charts and graphs. :)
declare function ebb:dateDecimalConverter($dT as xs:dateTime)
as xs:decimal?
{
let $year := year-from-dateTime($dT) ! xs:integer(.)
let $dayInYear := format-dateTime($dT, '[d]') ! xs:integer(.)
let $decimalDay := $dayInYear div 365
return $year + $decimalDay
};
(: CONVERT DURATION TO DECIMAL :)
(: ebb: The next user-defined function will convert the xs:duration datatype into a decimal value based on number of days.
 : So if we input a duration indicating 1 day, 6 hours, and 0 minutes, we should return 1.25 from this function.
 : Here's what we're calculating: There are 24 hours in a day. (Divide the H portion by 24) and add it to the days.
 : There are 60 minutes in an hour. (Divide the M portion by 60 * 24) and add it to hours.
 : There are 60 seconds in a minute (Divide the S portion by 60 * 60 * 24) and add it to minutes and hours
 : :)
declare function ebb:durationConverter($d as xs:integer, $h as xs:integer, $m as xs:integer, $s as xs:integer?)
as xs:decimal?
{
let $TDec := $h div 24 + $m div (60 * 24) + $s div (60 * 60 * 24)
return $d + $TDec
};
(: *******************END USER-DEFINED FUNCTIONS ********************** :)

let $launchDateTimes := $rocketColl//launch/@sDateTime
for $l in $launchDateTimes
(: To do date arithmetic, take a look at these functions: https://www.w3.org/TR/xpath-functions-31/#dates-times
 : We'll write a user-defined function to convert this datatype into a decimal notation. :)
let $lDec := ebb:dateDecimalConverter($l)
let $m := $rocketColl//launch[@sDateTime = $l]/preceding-sibling::sts
let $mID := $m  ! tokenize(., ':')[1]

let $duration := $m/following-sibling::duration/@time
(: ebb: To do duration arithmetic, start by looking at the functions here: https://www.w3.org/TR/xpath-functions-31/#durations
 : Let's try representing durations in terms of days with a decimal.
 : We'll write a user-defined function to convert hours, minutes, and seconds into a fraction of the day. :)
let $durDays := days-from-duration($duration)
let $durHours := hours-from-duration($duration)
let $durMins := minutes-from-duration($duration)
let $durSecs := seconds-from-duration($duration)
(: Now in line 43, we send our variables to our user-defined function for turning date datatypes into decimal values. :)
let $durDayDec := ebb:durationConverter($durDays, $durHours, $durMins, $durSecs)

order by $lDec
return concat('Launch Date: ', $l, ', mission: ', $mID, ': This Launch Decimal Date: ', $lDec, ': Duration: ', $duration, ': Decimal Notation:', $durDayDec)


changed beginning of time

changed beginning of time

(:~
: This is the Care Services Discovery stored query registry
: @version 1.0
: @see https://github.com/openhie/openinfoman
:
:)
module namespace csd_lsc = "https://github.com/openhie/openinfoman/csd_lsc";
import module namespace csd_psd = "https://github.com/openhie/openinfoman/csd_psd";
import module namespace csd_dm = "https://github.com/openhie/openinfoman/csd_dm";
declare namespace csd = "urn:ihe:iti:csd:2013";
declare default element  namespace   "urn:ihe:iti:csd:2013";

declare function csd_lsc:get_document_name($name) {
  csd_dm:document_source($name)
(:  concat("local_services_cache/",$name,".xml") :)
};

declare function csd_lsc:directory_exists($db,$name) {
  db:is-xml($db,csd_lsc:get_document_name($name))
};

declare updating function csd_lsc:empty_cache($db,$name)
{
  (
    csd_dm:empty($db,$name)
    ,csd_lsc:set_service_directory_mtime($db,$name,$csd_lsc:beginning_of_time)
   )

};

declare function csd_lsc:get_cache($db,$name)
{
 if (csd_lsc:directory_exists($db,$name)) then
    db:open($db,csd_lsc:get_document_name($name))
  else csd_dm:blank_directory()
};

declare variable $csd_lsc:beginning_of_time := '1970-01-01T00:00:00+00:00';
declare variable $csd_lsc:cache_meta_doc := 'local_cache_meta.xml';

declare function csd_lsc:get_cache_data($db,$name)
{
  if ( not( db:is-xml($db,$csd_lsc:cache_meta_doc)))  then
    if ($name) then
      ()
    else
      <cacheData/>
  else
    let $meta_doc :=  db:open($db,$csd_lsc:cache_meta_doc)
    return if ($name) then
      $meta_doc/cacheData/serviceCache[@name = $name]
    else
      $meta_doc/cacheData
};

declare updating function csd_lsc:drop_cache_data($db,$name)
{
  if ( not(db:is-xml($db,$csd_lsc:cache_meta_doc)))  then
    ()
  else
    let $meta_doc :=  db:open($db,$csd_lsc:cache_meta_doc)
      return if ($name) then
	delete node $meta_doc/cacheData/serviceCache[@name = $name]
      else
	delete node $meta_doc/cacheData/*

};

declare  function csd_lsc:cache_meta_exists($db) {
  db:is-xml($db,$csd_lsc:cache_meta_doc)
};

declare updating function csd_lsc:init_cache_meta($db) {
  if ( not(csd_lsc:cache_meta_exists($db)))  then
    db:add($db, <cacheData/>,$csd_lsc:cache_meta_doc)
  else
      ()
};

declare updating function csd_lsc:set_service_directory_mtime($db,$name,$mtime)
{
  ( csd_lsc:init_cache_meta($db)
  ,
  let $meta :=  db:open($db,$csd_lsc:cache_meta_doc)/cacheData
  return
    if (not(exists($meta/serviceCache[@name = $name])))  then
      insert node <serviceCache name="{$name}" mtime="{$csd_lsc:beginning_of_time}"/> into $meta
    else if (not(exists($meta/serviceCache[@name = $name]/@mtime))) then
      let $attr := attribute {"mtime"}{ $csd_lsc:beginning_of_time}
      return ( insert  node $attr into $meta/serviceCache[@name = $name])
    else
      replace value of node $meta/serviceCache[@name = $name]/@mtime with $mtime
  )

};

declare function csd_lsc:get_service_directory_mtime($db,$name)
{
  if ( db:is-xml($db,$csd_lsc:cache_meta_doc))  then
    let $mtime := text{db:open($db,$csd_lsc:cache_meta_doc)/cacheData/serviceCache[@name = $name]/@mtime}
    return if ($mtime) then
	$mtime
      else
	$csd_lsc:beginning_of_time
    else
      $csd_lsc:beginning_of_time

};

declare  updating  function csd_lsc:update_cache($db,$name)
{

  let $mtime :=  csd_lsc:get_service_directory_mtime($db,$name)
(:  querying against self during an update will cause a deadlock :)
(:  see or :)
(:  http://www.mail-archive.com/basex-talk@mailman.uni-konstanz.de/msg02999.htmlhttp://www.mail-archive.com/basex-talk@mailman.uni-konstanz.de/msg02999.html  :)
(:  possible work-around: http://docs.basex.org/wiki/Server_Protocol ? :)
  let $currtime := current-dateTime()
  let $result := csd_psd:poll_service_directory($db,$name,$mtime)
  let $cache_doc := csd_lsc:get_cache($db,$name)

  return (
    csd_lsc:refresh_doc($cache_doc,$result)
    ,csd_lsc:set_service_directory_mtime($db,$name,$currtime)

  )

};

declare updating function csd_lsc:refresh_doc($cache_doc,$updates)
{
  (
   csd_lsc:update_directory($cache_doc/csd:CSD/csd:organizationDirectory,$updates/(csd:CSD/csd:organizationDirectory|csd:organizationDirectory))
  ,csd_lsc:update_directory($cache_doc/csd:CSD/csd:facilityDirectory,$updates/(csd:CSD/csd:facilityDirectory|csd:facilityDirectory))
  ,csd_lsc:update_directory($cache_doc/csd:CSD/csd:serviceDirectory,$updates/(csd:CSD/csd:serviceDirectory|csd:serviceDirectory))
  ,csd_lsc:update_directory($cache_doc/csd:CSD/csd:providerDirectory,$updates/(csd:CSD/csd:providerDirectory|csd:providerDirectory))
  )
};

declare updating function csd_lsc:update_directory($oldDir,$newDir)
{
  for $new in  $newDir/*
  let $old := $oldDir/*[@entityID = $new/@entityID] (:there may be more than one:)
  let $t:=
    for ($o in $old)
    return delete node $old
  return  insert node $new into $oldDir
};

(:~
: This is the Care Services Discovery stored query registry
: @version 1.0
: @see https://github.com/openhie/openinfoman
:
:)
module namespace csd_lsc = "https://github.com/openhie/openinfoman/csd_lsc";
import module namespace csd_psd = "https://github.com/openhie/openinfoman/csd_psd";
import module namespace csd_dm = "https://github.com/openhie/openinfoman/csd_dm";
declare namespace csd = "urn:ihe:iti:csd:2013";
declare default element  namespace   "urn:ihe:iti:csd:2013";

declare function csd_lsc:get_document_name($name) {
  csd_dm:document_source($name)
(:  concat("local_services_cache/",$name,".xml") :)
};

declare function csd_lsc:directory_exists($db,$name) {
  db:is-xml($db,csd_lsc:get_document_name($name))
};

declare updating function csd_lsc:empty_cache($db,$name)
{
  (
    csd_dm:empty($db,$name)
    ,csd_lsc:set_service_directory_mtime($db,$name,$csd_lsc:beginning_of_time)
   )

};

declare function csd_lsc:get_cache($db,$name)
{
 if (csd_lsc:directory_exists($db,$name)) then
    db:open($db,csd_lsc:get_document_name($name))
  else csd_dm:blank_directory()
};

declare variable $csd_lsc:beginning_of_time := '2013-10-01T00:00:00+00:00';
declare variable $csd_lsc:cache_meta_doc := 'local_cache_meta.xml';

declare function csd_lsc:get_cache_data($db,$name)
{
  if ( not( db:is-xml($db,$csd_lsc:cache_meta_doc)))  then
    if ($name) then
      ()
    else
      <cacheData/>
  else
    let $meta_doc :=  db:open($db,$csd_lsc:cache_meta_doc)
    return if ($name) then
      $meta_doc/cacheData/serviceCache[@name = $name]
    else
      $meta_doc/cacheData
};

declare updating function csd_lsc:drop_cache_data($db,$name)
{
  if ( not(db:is-xml($db,$csd_lsc:cache_meta_doc)))  then
    ()
  else
    let $meta_doc :=  db:open($db,$csd_lsc:cache_meta_doc)
      return if ($name) then
	delete node $meta_doc/cacheData/serviceCache[@name = $name]
      else
	delete node $meta_doc/cacheData/*

};

declare  function csd_lsc:cache_meta_exists($db) {
  db:is-xml($db,$csd_lsc:cache_meta_doc)
};

declare updating function csd_lsc:init_cache_meta($db) {
  if ( not(csd_lsc:cache_meta_exists($db)))  then
    db:add($db, <cacheData/>,$csd_lsc:cache_meta_doc)
  else
      ()
};

declare updating function csd_lsc:set_service_directory_mtime($db,$name,$mtime)
{
  ( csd_lsc:init_cache_meta($db)
  ,
  let $meta :=  db:open($db,$csd_lsc:cache_meta_doc)/cacheData
  return
    if (not(exists($meta/serviceCache[@name = $name])))  then
      insert node <serviceCache name="{$name}" mtime="{$csd_lsc:beginning_of_time}"/> into $meta
    else if (not(exists($meta/serviceCache[@name = $name]/@mtime))) then
      let $attr := attribute {"mtime"}{ $csd_lsc:beginning_of_time}
      return ( insert  node $attr into $meta/serviceCache[@name = $name])
    else
      replace value of node $meta/serviceCache[@name = $name]/@mtime with $mtime
  )

};

declare function csd_lsc:get_service_directory_mtime($db,$name)
{
  if ( db:is-xml($db,$csd_lsc:cache_meta_doc))  then
    let $mtime := text{db:open($db,$csd_lsc:cache_meta_doc)/cacheData/serviceCache[@name = $name]/@mtime}
    return if ($mtime) then
	$mtime
      else
	$csd_lsc:beginning_of_time
    else
      $csd_lsc:beginning_of_time

};

declare  updating  function csd_lsc:update_cache($db,$name)
{

  let $mtime :=  csd_lsc:get_service_directory_mtime($db,$name)
(:  querying against self during an update will cause a deadlock :)
(:  see or :)
(:  http://www.mail-archive.com/basex-talk@mailman.uni-konstanz.de/msg02999.htmlhttp://www.mail-archive.com/basex-talk@mailman.uni-konstanz.de/msg02999.html  :)
(:  possible work-around: http://docs.basex.org/wiki/Server_Protocol ? :)
  let $currtime := current-dateTime()
  let $result := csd_psd:poll_service_directory($db,$name,$mtime)
  let $cache_doc := csd_lsc:get_cache($db,$name)

  return (
    csd_lsc:refresh_doc($cache_doc,$result)
    ,csd_lsc:set_service_directory_mtime($db,$name,$currtime)

  )

};

declare updating function csd_lsc:refresh_doc($cache_doc,$updates)
{
  (
   csd_lsc:update_directory($cache_doc/csd:CSD/csd:organizationDirectory,$updates/(csd:CSD/csd:organizationDirectory|csd:organizationDirectory))
  ,csd_lsc:update_directory($cache_doc/csd:CSD/csd:facilityDirectory,$updates/(csd:CSD/csd:facilityDirectory|csd:facilityDirectory))
  ,csd_lsc:update_directory($cache_doc/csd:CSD/csd:serviceDirectory,$updates/(csd:CSD/csd:serviceDirectory|csd:serviceDirectory))
  ,csd_lsc:update_directory($cache_doc/csd:CSD/csd:providerDirectory,$updates/(csd:CSD/csd:providerDirectory|csd:providerDirectory))
  )
};

declare updating function csd_lsc:update_directory($oldDir,$newDir)
{
  for $new in  $newDir/*
  let $old := $oldDir/*[@entityID = $new/@entityID] (:there may be more than one:)
  let $t:=
    for ($o in $old)
    return delete node $old
  return  insert node $new into $oldDir
};


removed jn:object function

removed jn:object function

jsoniq version "1.0";

(:
 : Copyright 2006-2012 The FLWOR Foundation.
 :
 : Licensed under the Apache License, Version 2.0 (the "License");
 : you may not use this file except in compliance with the License.
 : You may obtain a copy of the License at
 :
 : http://www.apache.org/licenses/LICENSE-2.0
 :
 : Unless required by applicable law or agreed to in writing, software
 : distributed under the License is distributed on an "AS IS" BASIS,
 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 : See the License for the specific language governing permissions and
 : limitations under the License.
:)

(:~
 : This module provides the functions defined by the JSONiq specification,
 : sections 1.7 (Functions) and 1.10 (Update Primitives). JSONiq extends
 : the XQuery specification to also deal with JSON data natively. See
 :
 :     http://jsoniq.org/
 :
 : for details.
 :
 : This module depends on having the JSONiq feature enabled in Zorba,
 : i.e., Zorba must be compiled with ZORBA_WITH_JSON.
 :
 : @author Markos Zaharioudakis, Matthias Brantner, Ghislain Fourny
 :)
module namespace jn = "http://jsoniq.org/functions";

import module namespace schema = "http://www.zorba-xquery.com/modules/schema";

declare namespace err = "http://www.w3.org/2005/xqt-errors";
declare namespace jerr = "http://jsoniq.org/errors";
declare namespace js = "http://jsoniq.org/types";

declare namespace ver = "http://www.zorba-xquery.com/options/versioning";
declare option ver:module-version "1.0";

(:~
 : This function decodes non-JSON types previously encoded with
 : jn:encode-for-roundtrip.
 : Calling this version of the function is equivalent to calling the
 : 2 argument version of the function with the second argument
 :
 :   { "prefix" : "Q{http://jsoniq.org/roundtrip}" }
 :
 : @param $items the items to be decoded.
 : @return the decoded items.
 :)
declare function jn:decode-from-roundtrip(
    $items as item()*) as item()* external;

(:~
 : This function decodes non-JSON types previously encoded with
 : jn:encode-for-roundtrip.
 : The $options parameter contains options for the decoding process.
 : Currently the only supported option is "prefix". It specifies the prefix
 : that determines if this function decodes an item.
 :
 : Example:
 :   jn:decode-from-roundtrip(
 :     { "nan" : { "pre-type" : "xs:double", "pre-value" : "NaN" } },
 :     { "prefix" : "pre-" }
 :   )
 : returns the same instance that would be constructed by
 :   { "nan" : xs:double("NaN") }
 :
 : So
 :   let $decoded := jn:decode-from-roundtrip(
 :           { "nan" : { "pre-type" : "xs:double", "pre-value" : "NaN" } },
 :           { "prefix" : "pre-" }
 :       )
 :   let $nan := $decoded("nan")
 :   return
 :       ($nan instance of xs:double, $nan)
 : returns
 :   true NaN
 :
 : @param $items the items to be decoded.
 : @param $options the decoding options.
 :
 : @error jerr:JNTY0023 if $options("prefix") is not a string
 :
 : @return the decoded items.
 :)
declare function jn:decode-from-roundtrip(
    $items as item()*,
    $options as object()) as item()* external;

(:~
 : This function recursively encodes non-JSON types in such a way that they
 : can be serialized as JSON while keeping roundtrip capability.
 : Calling this version of the function is equivalent to calling the
 : 2 argument version of the function with the second argument
 :
 :  {
 :    "prefix" : "Q{http://jsoniq.org/roundtrip}"
 :    "serialization-parameters" : <serialization-parameters xmlns="http://www.w3.org/2010/xslt-xquery-serialization"/>
 :  }
 :
 : Note: The computations are made with respect to the static context of the
 : caller, so that the schema type definitions are available.
 :
 : @param $items the items to be encoded.
 : @return the encoded items.
 :)
declare function jn:encode-for-roundtrip(
    $items as item()*) as item()* external;

(:~
 : This function recursively encodes non-JSON types in such a way that they
 : can be serialized as JSON while keeping roundtrip capability.
 :
 : Note: The computations are made with respect to the static context of the
 : caller, so that the schema type definitions are available.
 :
 : Example:
 :   jn:encode-for-roundtrip(
 :     { "nan" : xs:double("NaN") },
 :     { "prefix" : "pre-" }
 :   )
 : returns
 :   { "nan" : { "pre-type" : "xs:double", "pre-value" : "NaN" } }
 :
 : @param $items the items to be encoded.
 : @param $options the encoding options.
 :
 : @error jerr:JNTY0023 if $options("prefix") is not a string or
          $options("serialization-parameters") is not an element node
 : @error err:XQDY0027 if $options("serialization-parameters") is not a valid
 :        serialization-parameters element
 : @return the encoded items.
 :)
declare function jn:encode-for-roundtrip(
    $items as item()*,
    $options as object()) as item()* external;

(:~
 : This function parses a given string as JSON and returns a sequence
 : of Objects or Arrays.
 :
 : Please note that this function allows to parse sequences of whitespace
 : separated objects and arrays.
 :
 : @param $j A string containing a valid JSON text.
 :
 : @return A sequence of JSON Object or Array item.
 :
 : @error jerr:JNDY0021 if the given string is not valid JSON.
 :)
declare function jn:parse-json($j as xs:string?) as json-item()* external;

(:~
 : This function parses a given string as JSON and returns a sequence
 : of Objects or Arrays.
 :
 : @param $j A string containing a valid JSON text.
 : @param $o A JSON object defining options to configure the parser.
 : Allowed options are
 :

 :
jsoniq-multiple-top-level-items: allow parsing of sequences of JSON Objects and Arrays (boolean; default: true)

 :
jsoniq-strip-top-level-array: if the top-level JSON item is an array, strip it and return its elements as multiple top-level items (boolean; default: false)

 :

 :
 : @error jerr:JNDY0021 if the given string is not valid JSON or
 :   if jsoniq-multiple-top-level-items is false and there is additional
 :   content after the first JSON Object or Array.
 : @error jerr:JNTY0020 if the value for the option
 :   jsoniq-multiple-top-level-items is not of type xs:boolean.
 :
 : @return a sequence of JSON Object or Array item.
 :)
declare function jn:parse-json(
  $j as xs:string?,
  $o as object()) as json-item()* external;

(:~
 : Returns the names used in the object.
 : The names will be returned in an implementation-defined order
 :
 : @param $o A JSON Object.
 : @return The names of pairs in the object.
 :)
declare function jn:keys($o as object()) as xs:string* external;

(:~
 : Returns the value of a JSON Pair with a given name within a given JSON object.
 : If no such pair exists in the object, returns the empty sequence.
 :
 : @param $o A JSON Object.
 : @param $name The name of the pair whose value is to be retrieved
 : @return the value of specified pair within the given object, or the empty sequence.
 :)
(: obsolete - use $o($name) instead :)
declare function jn:value($o as object(), $name as xs:string) as item()? external;

(:~
 : Returns the size of a JSON Array. The size of an Array is
 : the number of members contained within it.
 :
 : @param $j A JSON Array.
 : @return The number of items in $j.
 :)
declare function jn:size($j as array()) as xs:integer external;

(:~
 : Returns the member of an Array at the specified position (starting from 1).
 : If the position is out of bounds of the array, returns the empty sequence.
 :
 : @param $a A JSON Array.
 : @param $p The position in the array.
 : @return The member at the specified position, or empty sequence.
 :)
(: obsolete - use $a($p) instead :)
declare function jn:member($a as array(), $p as xs:integer) as item()? external;

(:~
 : Creates an object from the specified pairs of another given object.
 : Specifically, for each name in $names, if the object $o has a pair with
 : that name, then a copy of that pair is included in the new object.
 :
 : @param $o A JSON Object.
 : @param $names The names of the pairs to copy out of $o and insert into the new object
 : @return The new object.
 :)
declare function jn:project($o as object(), $names as xs:string*) as object() external;

(:~
 : Returns the members of an Array.
 :
 : @param $a A JSON Array.
 : @return The members of the specified array.
 :)
declare function jn:members($o as array()) as item()* external;

(:~
 : Recursively "flatten" a JSON Array, by replacing any arrays with their
 : members. Equivalent to
 :
 :   define function jn:flatten($arg as array()) {
 :     for $value in jn:values($arg)
 :     return
 :       if ($value instance of array())
 :       then jn:flatten($value)
 :       else $value
 :   };
 :
 : @param $a A JSON Array.
 : @return The flattened version of $a.
 :)
declare function jn:flatten($a as array()) as item()* external;

(:~
 : Returns the JSON null.
 :
 : @return The JSON null.
 :)
declare function jn:null() as js:null external;

(:~
 : Tests whether the supplied atomic item is a JSON null.
 :
 : @param An atomic item.
 :
 : @return true if the item is of type js:null.
 :)
declare function jn:is-null($i as xs:anyAtomicType) as xs:boolean external;

jsoniq version "1.0";

(:
 : Copyright 2006-2012 The FLWOR Foundation.
 :
 : Licensed under the Apache License, Version 2.0 (the "License");
 : you may not use this file except in compliance with the License.
 : You may obtain a copy of the License at
 :
 : http://www.apache.org/licenses/LICENSE-2.0
 :
 : Unless required by applicable law or agreed to in writing, software
 : distributed under the License is distributed on an "AS IS" BASIS,
 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 : See the License for the specific language governing permissions and
 : limitations under the License.
:)

(:~
 : This module provides the functions defined by the JSONiq specification,
 : sections 1.7 (Functions) and 1.10 (Update Primitives). JSONiq extends
 : the XQuery specification to also deal with JSON data natively. See
 :
 :     http://jsoniq.org/
 :
 : for details.
 :
 : This module depends on having the JSONiq feature enabled in Zorba,
 : i.e., Zorba must be compiled with ZORBA_WITH_JSON.
 :
 : @author Markos Zaharioudakis, Matthias Brantner, Ghislain Fourny
 :)
module namespace jn = "http://jsoniq.org/functions";

import module namespace schema = "http://www.zorba-xquery.com/modules/schema";

declare namespace err = "http://www.w3.org/2005/xqt-errors";
declare namespace jerr = "http://jsoniq.org/errors";
declare namespace js = "http://jsoniq.org/types";

declare namespace ver = "http://www.zorba-xquery.com/options/versioning";
declare option ver:module-version "1.0";

(:~
 : This function decodes non-JSON types previously encoded with
 : jn:encode-for-roundtrip.
 : Calling this version of the function is equivalent to calling the
 : 2 argument version of the function with the second argument
 :
 :   { "prefix" : "Q{http://jsoniq.org/roundtrip}" }
 :
 : @param $items the items to be decoded.
 : @return the decoded items.
 :)
declare function jn:decode-from-roundtrip(
    $items as item()*) as item()* external;

(:~
 : This function decodes non-JSON types previously encoded with
 : jn:encode-for-roundtrip.
 : The $options parameter contains options for the decoding process.
 : Currently the only supported option is "prefix". It specifies the prefix
 : that determines if this function decodes an item.
 :
 : Example:
 :   jn:decode-from-roundtrip(
 :     { "nan" : { "pre-type" : "xs:double", "pre-value" : "NaN" } },
 :     { "prefix" : "pre-" }
 :   )
 : returns the same instance that would be constructed by
 :   { "nan" : xs:double("NaN") }
 :
 : So
 :   let $decoded := jn:decode-from-roundtrip(
 :           { "nan" : { "pre-type" : "xs:double", "pre-value" : "NaN" } },
 :           { "prefix" : "pre-" }
 :       )
 :   let $nan := $decoded("nan")
 :   return
 :       ($nan instance of xs:double, $nan)
 : returns
 :   true NaN
 :
 : @param $items the items to be decoded.
 : @param $options the decoding options.
 :
 : @error jerr:JNTY0023 if $options("prefix") is not a string
 :
 : @return the decoded items.
 :)
declare function jn:decode-from-roundtrip(
    $items as item()*,
    $options as object()) as item()* external;

(:~
 : This function recursively encodes non-JSON types in such a way that they
 : can be serialized as JSON while keeping roundtrip capability.
 : Calling this version of the function is equivalent to calling the
 : 2 argument version of the function with the second argument
 :
 :  {
 :    "prefix" : "Q{http://jsoniq.org/roundtrip}"
 :    "serialization-parameters" : <serialization-parameters xmlns="http://www.w3.org/2010/xslt-xquery-serialization"/>
 :  }
 :
 : Note: The computations are made with respect to the static context of the
 : caller, so that the schema type definitions are available.
 :
 : @param $items the items to be encoded.
 : @return the encoded items.
 :)
declare function jn:encode-for-roundtrip(
    $items as item()*) as item()* external;

(:~
 : This function recursively encodes non-JSON types in such a way that they
 : can be serialized as JSON while keeping roundtrip capability.
 :
 : Note: The computations are made with respect to the static context of the
 : caller, so that the schema type definitions are available.
 :
 : Example:
 :   jn:encode-for-roundtrip(
 :     { "nan" : xs:double("NaN") },
 :     { "prefix" : "pre-" }
 :   )
 : returns
 :   { "nan" : { "pre-type" : "xs:double", "pre-value" : "NaN" } }
 :
 : @param $items the items to be encoded.
 : @param $options the encoding options.
 :
 : @error jerr:JNTY0023 if $options("prefix") is not a string or
          $options("serialization-parameters") is not an element node
 : @error err:XQDY0027 if $options("serialization-parameters") is not a valid
 :        serialization-parameters element
 : @return the encoded items.
 :)
declare function jn:encode-for-roundtrip(
    $items as item()*,
    $options as object()) as item()* external;

(:~
 : This function parses a given string as JSON and returns a sequence
 : of Objects or Arrays.
 :
 : Please note that this function allows to parse sequences of whitespace
 : separated objects and arrays.
 :
 : @param $j A string containing a valid JSON text.
 :
 : @return A sequence of JSON Object or Array item.
 :
 : @error jerr:JNDY0021 if the given string is not valid JSON.
 :)
declare function jn:parse-json($j as xs:string?) as json-item()* external;

(:~
 : This function parses a given string as JSON and returns a sequence
 : of Objects or Arrays.
 :
 : @param $j A string containing a valid JSON text.
 : @param $o A JSON object defining options to configure the parser.
 : Allowed options are
 :

 :
jsoniq-multiple-top-level-items: allow parsing of sequences of JSON Objects and Arrays (boolean; default: true)

 :
jsoniq-strip-top-level-array: if the top-level JSON item is an array, strip it and return its elements as multiple top-level items (boolean; default: false)

 :

 :
 : @error jerr:JNDY0021 if the given string is not valid JSON or
 :   if jsoniq-multiple-top-level-items is false and there is additional
 :   content after the first JSON Object or Array.
 : @error jerr:JNTY0020 if the value for the option
 :   jsoniq-multiple-top-level-items is not of type xs:boolean.
 :
 : @return a sequence of JSON Object or Array item.
 :)
declare function jn:parse-json(
  $j as xs:string?,
  $o as object()) as json-item()* external;

(:~
 : Returns the names used in the object.
 : The names will be returned in an implementation-defined order
 :
 : @param $o A JSON Object.
 : @return The names of pairs in the object.
 :)
declare function jn:keys($o as object()) as xs:string* external;

(:~
 : Returns the value of a JSON Pair with a given name within a given JSON object.
 : If no such pair exists in the object, returns the empty sequence.
 :
 : @param $o A JSON Object.
 : @param $name The name of the pair whose value is to be retrieved
 : @return the value of specified pair within the given object, or the empty sequence.
 :)
(: obsolete - use $o($name) instead :)
declare function jn:value($o as object(), $name as xs:string) as item()? external;

(:~
 : Returns the size of a JSON Array. The size of an Array is
 : the number of members contained within it.
 :
 : @param $j A JSON Array.
 : @return The number of items in $j.
 :)
declare function jn:size($j as array()) as xs:integer external;

(:~
 : Returns the member of an Array at the specified position (starting from 1).
 : If the position is out of bounds of the array, returns the empty sequence.
 :
 : @param $a A JSON Array.
 : @param $p The position in the array.
 : @return The member at the specified position, or empty sequence.
 :)
(: obsolete - use $a($p) instead :)
declare function jn:member($a as array(), $p as xs:integer) as item()? external;

(:~
 : Creates an object from the specified pairs of another given object.
 : Specifically, for each name in $names, if the object $o has a pair with
 : that name, then a copy of that pair is included in the new object.
 :
 : @param $o A JSON Object.
 : @param $names The names of the pairs to copy out of $o and insert into the new object
 : @return The new object.
 :)
declare function jn:project($o as object(), $names as xs:string*) as object() external;

(:~
 : Returns the members of an Array.
 :
 : @param $a A JSON Array.
 : @return The members of the specified array.
 :)
declare function jn:members($o as array()) as item()* external;

(:~
 : Recursively "flatten" a JSON Array, by replacing any arrays with their
 : members. Equivalent to
 :
 :   define function jn:flatten($arg as array()) {
 :     for $value in jn:values($arg)
 :     return
 :       if ($value instance of array())
 :       then jn:flatten($value)
 :       else $value
 :   };
 :
 : @param $a A JSON Array.
 : @return The flattened version of $a.
 :)
declare function jn:flatten($a as array()) as item()* external;

(:~
 : This function allows dynamic object construction by merging all
 : its object parameters into a single object with a so-called "simple
 : object union". A simple object union creates a new object, the pairs
 : property of which is obtained by accumulating the pairs of all operand
 : objects. An error jerr:JNDY0003 is raised if two pairs with the same
 : name are encountered.
 :
 : @param $o A sequence of objects.
 :
 : @return The simple object union.
 :
 : @error jerr:JNDY0003 if there is a pair collision.
 :)
declare function jn:object($o as object()*) as object() external;

(:~
 : Returns the JSON null.
 :
 : @return The JSON null.
 :)
declare function jn:null() as js:null external;

(:~
 : Tests whether the supplied atomic item is a JSON null.
 :
 : @param An atomic item.
 :
 : @return true if the item is of type js:null.
 :)
declare function jn:is-null($i as xs:anyAtomicType) as xs:boolean external;