bug:40485 move comment to more sensible place

(:
 Copyright 2002-2016 MarkLogic Corporation.  All Rights Reserved.

 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 "1.0-ml";

(: This module supports code generation for entity services.
 : This module has no public API.  See entity-services.xqy for
 : the public interface.
 :)
module namespace es-codegen = "http://marklogic.com/entity-services-codegen";

import module namespace esi = "http://marklogic.com/entity-services-impl"
    at "entity-services-impl.xqy";

import module namespace functx   = "http://www.functx.com" at "/MarkLogic/functx/functx-1.0-nodoc-2007-01.xqy";

declare namespace es = "http://marklogic.com/entity-services";
declare namespace tde = "http://marklogic.com/xdmp/tde";

declare function es-codegen:conversion-module-generate(
    $entity-type as map:map
) as document-node()
{
    let $default-base-uri := "http://example.org/"
    let $info := map:get($entity-type, "info")
    let $title := map:get($info, "title")
    let $prefix := lower-case(substring($title,1,1)) || substring($title,2)
    let $version:= map:get($info, "version")
    let $definitions := map:get($entity-type, "definitions")
    let $base-uri := fn:head((map:get($info, "baseUri"), $default-base-uri))
    let $base-uri :=
            if (fn:matches($base-uri, "[#/]$"))
            then $base-uri
            else concat($base-uri, "#")
    return
document {
<conversion-module>xquery version "1.0-ml";

(:
 : This module was generated by MarkLogic Entity Services.
 : The source entity type document was {$title}-{$version}
 :
 : To use this module, examine how you wish to extract data from sources,
 : and modify the various extract-instance-{{X}} functions to
 : create the instances you wish.
 :
 : You may wish to/need to alter
 : 1.  values.  For example, creating duration values from decimal months.
 : 2.  references.  This conversion module assumes you want to denormalize
 :     instances when storing them in documents.  You may choose to remove
 :     code that denormalizes, and just include reference values in your instances
 :     instead.
 : 3.  Source XPath expressions.  The data coming into the extract-instance-{{X}}
 :     functions will probably not be exactly what this module predicts.
 :
 : After modifying this file, put it in your project for deployment to the modules
 : database of your application, and check it into your source control system.
 :
 : Modification History:
 :   Generated at timestamp: {fn:current-dateTime()}
 :   Persisted by AUTHOR
 :   Date: DATE
 :)
module namespace {$prefix} = "{$base-uri}{$title}-{$version}";

import module namespace es = "http://marklogic.com/entity-services"
    at "/MarkLogic/entity-services/entity-services.xqy";

(:
 :  extract-instance-{{entity-type}} functions
 :
 :  These functions take together take a source document and create a nested
 :  map structure from it.
 :  The resulting map is used by instance-to-canonical-xml to create documents
 :  in the database.
 :
 :  It is expected that an implementer will edit at least XPath expressions in
 :  the extraction functions.  It is less likely that you will want to edit
 :  the instance-to-canonical-xml or envelope functions.
 :)
{
    for $entity-type-key in map:keys(map:get($entity-type, "definitions"))
    return
    <extract-instance>
(:~
 : Creates a map:map representation of an entity instance from some source
 : document.
 : @param $source-node  A document or node that contains data for populating a {$entity-type-key}
 : @return A map:map instance that holds the data for this entity type.
 :)
declare function {$prefix}:extract-instance-{$entity-type-key}(
    $source-node as node()
) as map:map
{{
    json:object()
        (: This line identifies the type of this instance.  Do not change it. :)
        =>map:with('$type', '{ $entity-type-key }')
        (: This line adds the original source document as an attachment.
         : If this entity type is not the root of a document, you should remove this.
         : If the source document is JSON, use
         : =>map:with('$attachments', xdmp:quote($source-node))
         : because you cannot preserve JSON nodes with the XML envelope verbatim.
         :)
        =>map:with('$attachments', $source-node)
        (: The following lines are generated from the '{ $entity-type-key }' entity type
         : You need to ensure that all of the property paths are correct for your source
         : data to populate instances.  The general pattern is
         : =>map:with('keyName', data($source-node/path/to/data/in/the/source))
         : but you may also wish to convert values
         : =>map:with('dateKeyName', xdmp:parse-dateTime("[Y0001]-[M01]-[D01]T[h01]:[m01]:[s01].[f1][Z]", $source-node/path/to/data/in/the/source))
         : You can also implement lookup functions,
         : =>map:with('lookupKey', cts:search( collection('customers'), string($source-node/path/to/lookup/key))/id
         : or populate the instance with constants.
         : =>map:with('constantValue', 10)
         : Once you've customized this function, write a test with expected inputs, and a test instance document
         : created with es:entity-type-get-test-instances($entity-type)
         :)
    {
    (: Begin code generation block :)
    let $this-type := map:get($definitions, $entity-type-key)
    let $properties-map := map:get($this-type, "properties")
    let $properties-keys := map:keys($properties-map)
    for $property-key in map:keys($properties-map)
    let $is-array :=
            map:get(map:get($properties-map, $property-key), "datatype")
            eq "array"
    let $wrap-if-array := function($str) {
            if ($is-array)
            then concat("json:to-array(", $str, " ! data(.))")
            else concat("data(", $str, ")")
        }
    let $ref :=
        if ($is-array)
        then map:get(map:get(map:get($properties-map, $property-key), "items"), "$ref")
        else map:get(map:get($properties-map, $property-key), "$ref")
    let $path-to-property := concat("$source-node/", $entity-type-key, "/", $property-key)
    let $property-comment :=
        if (empty($ref))
        then ""
        else if (contains($ref, "#/definitions"))
        then ""
        else concat(
      '    (: The following property assigment comes from an external reference.',
'
         : Its generated value probably requires developer attention.',
'
         :)',
'
    ')
    let $value :=
        if (empty($ref))
        then
            $wrap-if-array($path-to-property)
        else
            if(contains($ref, "#/definitions"))
            then
            concat("
            if (", $path-to-property, "/element())",
                   "
            then json:to-array(",
                    $path-to-property, " ! ", $prefix, ":extract-instance-", replace($ref, "#/definitions/", ""), "(.))",
                   "
            else data(",
                   $path-to-property,
                   ")")
            else
               concat(
                $path-to-property, "/node()")

    (: if a property is required, use map:with to force inclusion :)
    let $function-call-string :=
        if ($property-key = ( map:get($this-type, "primaryKey"), json:array-values( map:get($this-type, "required")) ))
        then "       =>map:with("
        else "    =>es:optional("
    return
    concat($property-comment,
            $function-call-string,
            functx:pad-string-to-length("'" || $property-key || "',", " ", max((  (string-length($property-key)+4), 25) )+1 ),
            $value,
            ")
   "
          )
    (: end code generation block :)
    }
}};
    </extract-instance>/text()
}

(:~
 : Turns an entity instance into an XML structure.
 : This out-of-the box implementation traverses a map structure
 : and turns it deterministically into an XML tree.
 : Using this function as-is should be sufficient for most use
 : cases, and will play well with other generated artifacts.
 : @param $entity-instance A map:map instance returned from one of the extract-instance
 :    functions.
 : @return An XML element that encodes the instance.
 :)
declare function {$prefix}:instance-to-canonical-xml(
    $entity-instance as map:map
) as element()
{{
    (: Construct an element that is named the same as the Entity Type :)
    element {{ map:get($entity-instance, "$type") }}  {{
        for $key in map:keys($entity-instance)
        let $instance-property := map:get($entity-instance, $key)
        where ($key castable as xs:NCName and $key ne "$type")
        return
            typeswitch ($instance-property)
            (: This branch handles embedded objects.  You can choose to prune
               an entity's representation of extend it with lookups here. :)
            case json:object+
                return
                    for $prop in $instance-property
                    return element {{ $key }} {{ {$prefix}:instance-to-canonical-xml($prop) }}
            (: An array can also treated as multiple elements :)
            case json:array
                return
                    for $val in json:array-values($instance-property)
                    return
                        if ($val instance of json:object)
                        then element {{ $key }} {{ {$prefix}:instance-to-canonical-xml($val) }}
                        else element {{ $key }} {{ $val }}
            (: A sequence of values should be simply treated as multiple elements :)
            case item()+
                return
                    for $val in $instance-property
                    return element {{ $key }} {{ $val }}
            default return element {{ $key }} {{ $instance-property }}
    }}
}};

(:
 : Wraps a canonical instance (returned by instance-to-canonical-xml())
 : within an envelope patterned document, along with the source
 : document, which is stored in an attachments section.
 : @param $entity-instance an instance, as returned by an extract-instance
 : function
 : @return A document which wraps both the canonical instance and source docs.
 :)
declare function {$prefix}:instance-to-envelope(
    $entity-instance as map:map
) as document-node()
{{
    document {{
        element es:envelope {{
            element es:instance {{
                element es:info {{
                    element es:title {{ map:get($entity-instance,'$type') }},
                    element es:version {{ "{$version}" }}
                }},
                {$prefix}:instance-to-canonical-xml($entity-instance)
            }},
            element es:attachments {{
                map:get($entity-instance, "$attachments")
            }}
        }}
    }}
}};

</conversion-module>/text()
}

};

(:
 Copyright 2002-2016 MarkLogic Corporation.  All Rights Reserved.

 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 "1.0-ml";

(: This module supports code generation for entity services.
 : This module has no public API.  See entity-services.xqy for
 : the public interface.
 :)
module namespace es-codegen = "http://marklogic.com/entity-services-codegen";

import module namespace esi = "http://marklogic.com/entity-services-impl"
    at "entity-services-impl.xqy";

import module namespace functx   = "http://www.functx.com" at "/MarkLogic/functx/functx-1.0-nodoc-2007-01.xqy";

declare namespace es = "http://marklogic.com/entity-services";
declare namespace tde = "http://marklogic.com/xdmp/tde";

declare function es-codegen:conversion-module-generate(
    $entity-type as map:map
) as document-node()
{
    let $default-base-uri := "http://example.org/"
    let $info := map:get($entity-type, "info")
    let $title := map:get($info, "title")
    let $prefix := lower-case(substring($title,1,1)) || substring($title,2)
    let $version:= map:get($info, "version")
    let $definitions := map:get($entity-type, "definitions")
    let $base-uri := fn:head((map:get($info, "baseUri"), $default-base-uri))
    let $base-uri :=
            if (fn:matches($base-uri, "[#/]$"))
            then $base-uri
            else concat($base-uri, "#")
    return
document {
<conversion-module>xquery version "1.0-ml";

(:
 : This module was generated by MarkLogic Entity Services.
 : The source entity type document was {$title}-{$version}
 :
 : To use this module, examine how you wish to extract data from sources,
 : and modify the various extract-instance-{{X}} functions to
 : create the instances you wish.
 :
 : You may wish to/need to alter
 : 1.  values.  For example, creating duration values from decimal months.
 : 2.  references.  This conversion module assumes you want to denormalize
 :     instances when storing them in documents.  You may choose to remove
 :     code that denormalizes, and just include reference values in your instances
 :     instead.
 : 3.  Source XPath expressions.  The data coming into the extract-instance-{{X}}
 :     functions will probably not be exactly what this module predicts.
 :
 : After modifying this file, put it in your project for deployment to the modules
 : database of your application, and check it into your source control system.
 :
 : Modification History:
 :   Generated at timestamp: {fn:current-dateTime()}
 :   Persisted by AUTHOR
 :   Date: DATE
 :)
module namespace {$prefix} = "{$base-uri}{$title}-{$version}";

import module namespace es = "http://marklogic.com/entity-services"
    at "/MarkLogic/entity-services/entity-services.xqy";

(:
 :  extract-instance-{{entity-type}} functions
 :
 :  These functions take together take a source document and create a nested
 :  map structure from it.
 :  The resulting map is used by instance-to-canonical-xml to create documents
 :  in the database.
 :
 :  It is expected that an implementer will edit at least XPath expressions in
 :  the extraction functions.  It is less likely that you will want to edit
 :  the instance-to-canonical-xml or envelope functions.
 :)
{
    for $entity-type-key in map:keys(map:get($entity-type, "definitions"))
    return
    <extract-instance>
(:~
 : Creates a map:map representation of an entity instance from some source
 : document.
 : @param $source-node  A document or node that contains data for populating a {$entity-type-key}
 : @return A map:map instance that holds the data for this entity type.
 :)
declare function {$prefix}:extract-instance-{$entity-type-key}(
    $source-node as node()
) as map:map
{{
    json:object()
        (: This line identifies the type of this instance.  Do not change it. :)
        =>map:with('$type', '{ $entity-type-key }')
        (: This line adds the original source document as an attachment.
         : If this entity type is not the root of a document, you should remove this.
         : If the source document is JSON, use
         : =>map:with('$attachments', xdmp:quote($source-node))
         : because you cannot preserve JSON nodes with the XML envelope verbatim.
         :)
        =>map:with('$attachments', $source-node)
        (: The following lines are generated from the '{ $entity-type-key }' entity type
         : You need to ensure that all of the property paths are correct for your source
         : data to populate instances.  The general pattern is
         : =>map:with('keyName', data($source-node/path/to/data/in/the/source))
         : but you may also wish to convert values
         : =>map:with('dateKeyName', xdmp:parse-dateTime("[Y0001]-[M01]-[D01]T[h01]:[m01]:[s01].[f1][Z]", $source-node/path/to/data/in/the/source))
         : You can also implement lookup functions,
         : =>map:with('lookupKey', cts:search( collection('customers'), string($source-node/path/to/lookup/key))/id
         : or populate the instance with constants.
         : =>map:with('constantValue', 10)
         : Once you've customized this function, write a test with expected inputs, and a test instance document
         : created with es:entity-type-get-test-instances($entity-type)
         :)
    {
    (: Begin code generation block :)
    let $this-type := map:get($definitions, $entity-type-key)
    let $properties-map := map:get($this-type, "properties")
    let $properties-keys := map:keys($properties-map)
    for $property-key in map:keys($properties-map)
    let $is-array :=
            map:get(map:get($properties-map, $property-key), "datatype")
            eq "array"
    let $wrap-if-array := function($str) {
            if ($is-array)
            then concat("json:to-array(", $str, " ! data(.))")
            else concat("data(", $str, ")")
        }
    let $ref :=
        if ($is-array)
        then map:get(map:get(map:get($properties-map, $property-key), "items"), "$ref")
        else map:get(map:get($properties-map, $property-key), "$ref")
    let $path-to-property := concat("$source-node/", $entity-type-key, "/", $property-key)
    let $value :=
        if (empty($ref))
        then
            $wrap-if-array($path-to-property)
        else
            if(contains($ref, "#/definitions"))
            then
            concat("
            if (", $path-to-property, "/element())",
                   "
            then json:to-array(",
                    $path-to-property, " ! ", $prefix, ":extract-instance-", replace($ref, "#/definitions/", ""), "(.))",
                   "
            else data(",
                   $path-to-property,
                   ")")
            else
               concat(
                '(: The following assignment comes from an external reference.  Its value probably requires developer attention :)',
                $path-to-property, "/node()")

    (: if a property is required, use map:with to force inclusion :)
    let $function-call-string :=
        if ($property-key = ( map:get($this-type, "primaryKey"), json:array-values( map:get($this-type, "required")) ))
        then "       =>map:with("
        else "    =>es:optional("
    return
    concat($function-call-string,
            functx:pad-string-to-length("'" || $property-key || "',", " ", max((  (string-length($property-key)+4), 25) )+1 ),
            $value,
            ")
   "
          )
    (: end code generation block :)
    }
}};
    </extract-instance>/text()
}

(:~
 : Turns an entity instance into an XML structure.
 : This out-of-the box implementation traverses a map structure
 : and turns it deterministically into an XML tree.
 : Using this function as-is should be sufficient for most use
 : cases, and will play well with other generated artifacts.
 : @param $entity-instance A map:map instance returned from one of the extract-instance
 :    functions.
 : @return An XML element that encodes the instance.
 :)
declare function {$prefix}:instance-to-canonical-xml(
    $entity-instance as map:map
) as element()
{{
    (: Construct an element that is named the same as the Entity Type :)
    element {{ map:get($entity-instance, "$type") }}  {{
        for $key in map:keys($entity-instance)
        let $instance-property := map:get($entity-instance, $key)
        where ($key castable as xs:NCName and $key ne "$type")
        return
            typeswitch ($instance-property)
            (: This branch handles embedded objects.  You can choose to prune
               an entity's representation of extend it with lookups here. :)
            case json:object+
                return
                    for $prop in $instance-property
                    return element {{ $key }} {{ {$prefix}:instance-to-canonical-xml($prop) }}
            (: An array can also treated as multiple elements :)
            case json:array
                return
                    for $val in json:array-values($instance-property)
                    return
                        if ($val instance of json:object)
                        then element {{ $key }} {{ {$prefix}:instance-to-canonical-xml($val) }}
                        else element {{ $key }} {{ $val }}
            (: A sequence of values should be simply treated as multiple elements :)
            case item()+
                return
                    for $val in $instance-property
                    return element {{ $key }} {{ $val }}
            default return element {{ $key }} {{ $instance-property }}
    }}
}};

(:
 : Wraps a canonical instance (returned by instance-to-canonical-xml())
 : within an envelope patterned document, along with the source
 : document, which is stored in an attachments section.
 : @param $entity-instance an instance, as returned by an extract-instance
 : function
 : @return A document which wraps both the canonical instance and source docs.
 :)
declare function {$prefix}:instance-to-envelope(
    $entity-instance as map:map
) as document-node()
{{
    document {{
        element es:envelope {{
            element es:instance {{
                element es:info {{
                    element es:title {{ map:get($entity-instance,'$type') }},
                    element es:version {{ "{$version}" }}
                }},
                {$prefix}:instance-to-canonical-xml($entity-instance)
            }},
            element es:attachments {{
                map:get($entity-instance, "$attachments")
            }}
        }}
    }}
}};

</conversion-module>/text()
}

};


bug:38756 Change constructors to json:object from map:map

(:
 Copyright 2002-2016 MarkLogic Corporation.  All Rights Reserved.

 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 "1.0-ml";

module namespace es-codegen = "http://marklogic.com/entity-services-codegen";

import module namespace esi = "http://marklogic.com/entity-services-impl"
    at "entity-services-impl.xqy";

declare namespace es = "http://marklogic.com/entity-services";
declare namespace tde = "http://marklogic.com/xdmp/tde";

(:~
 : Generates an XQuery module that can be customized and used
 : to support transforms associated with an entity type
 : @param $entity-type  An entity type object.
 : @return An XQuery module (text) that can be edited and installed in a modules database.
 :)
declare function es-codegen:conversion-module-generate(
    $entity-type as map:map
) as document-node()
{
    let $default-base-uri := "http://example.org/"
    let $info := map:get($entity-type, "info")
    let $prefix := map:get($info, "title")
    let $version:= map:get($info, "version")
    let $definitions := map:get($entity-type, "definitions")
    let $base-uri := fn:head((map:get($info, "baseUri"), $default-base-uri))
    let $base-uri :=
            if (fn:matches($base-uri, "[#/]$"))
            then $base-uri
            else concat($base-uri, "#")
    return
document {
<conversion-module>
xquery version "1.0-ml";

(: This module was generated by MarkLogic Entity Services.
 : The source entity type document was {$prefix}-{$version}
 :
 : Modification History:
 :   Generated at timestamp: {fn:current-dateTime()}
 :   Persisted by AUTHOR
 :   Date: DATE
 :)
module namespace {$prefix} = "{$base-uri}{$prefix}-{$version}";

import module namespace es = "http://marklogic.com/entity-services"
    at "/MarkLogic/entity-services/entity-services.xqy";

(: extract-instance-{{entity-type}} Functions :)
(: These functions can be customized to reflect a data source for an entity type :)
{ (: iterate over entity types to make extract instance stubs :)
    for $entity-type-key in map:keys(map:get($entity-type, "definitions"))
    return
    <extract-instance>
declare function {$prefix}:extract-instance-{$entity-type-key}(
    $source-node as node()
) as map:map
{{
    let $instance := json:object()
    let $_ := map:put($instance, "$type", "{$entity-type-key}")
    let $_ := map:put($instance, "$attachments", $source-node)
    {
    let $this-type := map:get($definitions, $entity-type-key)
    let $properties-map := map:get($this-type, "properties")
    let $properties-keys := map:keys($properties-map)
    for $property-key in map:keys($properties-map)
    let $is-array := map:get(map:get($properties-map, $property-key), "datatype") eq "array"
    let $ref :=
        if ($is-array)
        then map:get(map:get(map:get($properties-map, $property-key), "items"), "$ref")
        else map:get(map:get($properties-map, $property-key), "$ref")
    let $path-to-property := concat("$source-node/", $entity-type-key, "/", $property-key)
    let $value :=
        if (empty($ref))
        then
            concat($path-to-property, " ! data(.)")
        else
            if(contains($ref, "#/definitions"))
            then
            concat("if (not(",
                    $path-to-property,
                    "/element()))
then ",
                    "data(", $path-to-property, ")",
                    "
else ",
                    $path-to-property,
                    " ! ",
                    $prefix,
                    ":extract-instance-",
                    replace($ref, "#/definitions/", ""),
                    "(.)"
                    )
            else
               concat($path-to-property, "/node()")

    return

    concat("let $_ := if (empty( (",
            $path-to-property,
            ")))
",
            "         then ()
",
            "         else map:put($instance, '", $property-key, "', ",$value, ")
   "
          )
    }
        return $instance
}};
    </extract-instance>/text()
}

(: instance-to-canonical-xml function
 : Depending on the relationships among your entity types
 : you may wish to modify sections of this function
 : to meet your own purposes.
 :)
declare function {$prefix}:instance-to-canonical-xml(
    $entity-instance as map:map
) as element(es:instance)
{{
    let $title := "{$prefix}"
    let $version := "{$version}"
    let $instance-keys := map:keys($entity-instance)
    let $instance-node :=
        (: Construct the instance wrapper element itself :)
        element es:instance {{
            (: Construct the metadata for the instance :)
            element es:info {{
                element es:title {{ $title }},
                element es:version {{ $version }}
                (: TODO id :)
            }},
            (: Construct an element that is named the same as the Entity Type :)
            element {{ map:get($entity-instance, "$type") }}  {{
                for $key in $instance-keys
                let $instance-property := map:get($entity-instance, $key)
                where ($key castable as xs:NCName and $key ne "$type")
                return
                    typeswitch ($instance-property)
                    (: This branch handles embedded objects.  You can choose to prune
                       an entity's representation of extend it with lookups here. :)
                    case json:object+
                        return
                            for $prop in $instance-property
                            return element {{ $key }} {{ {$prefix}:instance-to-canonical-xml($prop)/(*[exists(./*)] except es:info) }}
                    (: A sequence of values should be simply treated as multiple elements :)
                    case item()+
                        return
                            for $val in $instance-property
                            return element {{ $key }} {{ $val }}
                    (: An array by convention can also treated as multiple elements :)
                    case json:array
                        return
                            for $val in json:array-values($instance-property)
                            return element {{ $key }} {{ $val }}
                    default return element {{ $key }} {{ $instance-property }}
            }}
        }}
    return $instance-node
}};

(: instance-to-envelope
 : This function is used to wrap sources and entity instances
 : within the same document
 :)
declare function {$prefix}:instance-to-envelope(
    $entity-instance as map:map
) as element(es:envelope)
{{
    element es:envelope {{
        {$prefix}:instance-to-canonical-xml($entity-instance),
        element es:attachments {{
            map:get($entity-instance, "$attachments")
        }}
    }}
}};

(: instance-from-document
 : if you have modified instance-to-envelope
 : you may need also to modify this function
 :)
declare function {$prefix}:instance-from-document(
    $document as document-node()
) as map:map*
{{
    let $xml-from-document := {$prefix}:instance-xml-from-document($document)
    for $root-instance in $xml-from-document
        let $instance := json:object()
        let $_ :=
            for $property in $root-instance/*
            return
                if ($property/element())
                then map:put($instance, local-name($property), $property/* ! {$prefix}:child-instance(.))
                else map:put($instance, local-name($property), data($property))
        return $instance
}};

declare function {$prefix}:child-instance(
    $element as element()
) as map:map*
{{
    let $child := json:object()
    let $_ :=
        for $property in $element/*
        return
            if ($property/element())
            then map:put($child, local-name($property), {$prefix}:child-instance($property))
            else map:put($child, local-name($property), data($property))
    return $child
}};

(:~
 : Returns all XML from within a document envelope except the es:info.
 : This function is generic enough not to require customization for
 : most entity type implementations.
 :)
declare function {$prefix}:instance-xml-from-document(
    $document as document-node()
) as element()
{{
    $document//es:instance/(* except es:info)
}};

declare function {$prefix}:instance-json-from-document(
    $document as document-node()
) as object-node()
{{
    let $instance := {$prefix}:instance-from-document($document)
    return xdmp:to-json($instance)/node()
}};

declare function {$prefix}:instance-get-attachments(
    $document as document-node()
) as element()*
{{
    $document//es:attachments/*
}};

</conversion-module>/text()
}

};

(:
 Copyright 2002-2016 MarkLogic Corporation.  All Rights Reserved.

 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 "1.0-ml";

module namespace es-codegen = "http://marklogic.com/entity-services-codegen";

import module namespace esi = "http://marklogic.com/entity-services-impl"
    at "entity-services-impl.xqy";

declare namespace es = "http://marklogic.com/entity-services";
declare namespace tde = "http://marklogic.com/xdmp/tde";

(:~
 : Generates an XQuery module that can be customized and used
 : to support transforms associated with an entity type
 : @param $entity-type  An entity type object.
 : @return An XQuery module (text) that can be edited and installed in a modules database.
 :)
declare function es-codegen:conversion-module-generate(
    $entity-type as map:map
) as document-node()
{
    let $default-base-uri := "http://example.org/"
    let $info := map:get($entity-type, "info")
    let $prefix := map:get($info, "title")
    let $version:= map:get($info, "version")
    let $definitions := map:get($entity-type, "definitions")
    let $base-uri := fn:head((map:get($info, "baseUri"), $default-base-uri))
    let $base-uri :=
            if (fn:matches($base-uri, "[#/]$"))
            then $base-uri
            else concat($base-uri, "#")
    return
document {
<conversion-module>
xquery version "1.0-ml";

(: This module was generated by MarkLogic Entity Services.
 : The source entity type document was {$prefix}-{$version}
 :
 : Modification History:
 :   Generated at timestamp: {fn:current-dateTime()}
 :   Persisted by AUTHOR
 :   Date: DATE
 :)
module namespace {$prefix} = "{$base-uri}{$prefix}-{$version}";

import module namespace es = "http://marklogic.com/entity-services"
    at "/MarkLogic/entity-services/entity-services.xqy";

(: extract-instance-{{entity-type}} Functions :)
(: These functions can be customized to reflect a data source for an entity type :)
{ (: iterate over entity types to make extract instance stubs :)
    for $entity-type-key in map:keys(map:get($entity-type, "definitions"))
    return
    <extract-instance>
declare function {$prefix}:extract-instance-{$entity-type-key}(
    $source-node as node()
) as map:map
{{
    let $instance := json:object()
    let $_ := map:put($instance, "$type", "{$entity-type-key}")
    let $_ := map:put($instance, "$attachments", $source-node)
    {
    let $this-type := map:get($definitions, $entity-type-key)
    let $properties-map := map:get($this-type, "properties")
    let $properties-keys := map:keys($properties-map)
    for $property-key in map:keys($properties-map)
    let $is-array := map:get(map:get($properties-map, $property-key), "datatype") eq "array"
    let $ref :=
        if ($is-array)
        then map:get(map:get(map:get($properties-map, $property-key), "items"), "$ref")
        else map:get(map:get($properties-map, $property-key), "$ref")
    let $path-to-property := concat("$source-node/", $entity-type-key, "/", $property-key)
    let $value :=
        if (empty($ref))
        then
            concat($path-to-property, " ! data(.)")
        else
            if(contains($ref, "#/definitions"))
            then
            concat("if (not(",
                    $path-to-property,
                    "/element()))
then ",
                    "data(", $path-to-property, ")",
                    "
else ",
                    $path-to-property,
                    " ! ",
                    $prefix,
                    ":extract-instance-",
                    replace($ref, "#/definitions/", ""),
                    "(.)"
                    )
            else
               concat($path-to-property, "/node()")

    return

    concat("let $_ := if (empty( (",
            $path-to-property,
            ")))
",
            "         then ()
",
            "         else map:put($instance, '", $property-key, "', ",$value, ")
   "
          )
    }
        return $instance
}};
    </extract-instance>/text()
}

(: instance-to-canonical-xml function
 : Depending on the relationships among your entity types
 : you may wish to modify sections of this function
 : to meet your own purposes.
 :)
declare function {$prefix}:instance-to-canonical-xml(
    $entity-instance as map:map
) as element(es:instance)
{{
    let $title := "{$prefix}"
    let $version := "{$version}"
    let $instance-keys := map:keys($entity-instance)
    let $instance-node :=
        (: Construct the instance wrapper element itself :)
        element es:instance {{
            (: Construct the metadata for the instance :)
            element es:info {{
                element es:title {{ $title }},
                element es:version {{ $version }}
                (: TODO id :)
            }},
            (: Construct an element that is named the same as the Entity Type :)
            element {{ map:get($entity-instance, "$type") }}  {{
                for $key in $instance-keys
                let $instance-property := map:get($entity-instance, $key)
                where ($key castable as xs:NCName and $key ne "$type")
                return
                    typeswitch ($instance-property)
                    (: This branch handles embedded objects.  You can choose to prune
                       an entity's representation of extend it with lookups here. :)
                    case json:object+
                        return
                            for $prop in $instance-property
                            return element {{ $key }} {{ {$prefix}:instance-to-canonical-xml($prop)/(*[exists(./*)] except es:info) }}
                    (: A sequence of values should be simply treated as multiple elements :)
                    case item()+
                        return
                            for $val in $instance-property
                            return element {{ $key }} {{ $val }}
                    (: An array by convention can also treated as multiple elements :)
                    case json:array
                        return
                            for $val in json:array-values($instance-property)
                            return element {{ $key }} {{ $val }}
                    default return element {{ $key }} {{ $instance-property }}
            }}
        }}
    return $instance-node
}};

(: instance-to-envelope
 : This function is used to wrap sources and entity instances
 : within the same document
 :)
declare function {$prefix}:instance-to-envelope(
    $entity-instance as map:map
) as element(es:envelope)
{{
    element es:envelope {{
        {$prefix}:instance-to-canonical-xml($entity-instance),
        element es:attachments {{
            map:get($entity-instance, "$attachments")
        }}
    }}
}};

(: instance-from-document
 : if you have modified instance-to-envelope
 : you may need also to modify this function
 :)
declare function {$prefix}:instance-from-document(
    $document as document-node()
) as map:map*
{{
    let $xml-from-document := {$prefix}:instance-xml-from-document($document)
    for $root-instance in $xml-from-document
        let $instance := map:map()
        let $_ :=
            for $property in $root-instance/*
            return
                if ($property/element())
                then map:put($instance, local-name($property), $property/* ! {$prefix}:child-instance(.))
                else map:put($instance, local-name($property), data($property))
        return $instance
}};

declare function {$prefix}:child-instance(
    $element as element()
) as map:map*
{{
    let $child := map:map()
    let $_ :=
        for $property in $element/*
        return
            if ($property/element())
            then map:put($child, local-name($property), {$prefix}:child-instance($property))
            else map:put($child, local-name($property), data($property))
    return $child
}};

(:~
 : Returns all XML from within a document envelope except the es:info.
 : This function is generic enough not to require customization for
 : most entity type implementations.
 :)
declare function {$prefix}:instance-xml-from-document(
    $document as document-node()
) as element()
{{
    $document//es:instance/(* except es:info)
}};

declare function {$prefix}:instance-json-from-document(
    $document as document-node()
) as object-node()
{{
    let $instance := {$prefix}:instance-from-document($document)
    return xdmp:to-json($instance)/node()
}};

declare function {$prefix}:instance-get-attachments(
    $document as document-node()
) as element()*
{{
    $document//es:attachments/*
}};

</conversion-module>/text()
}

};


fix to expat info display.

fix to expat info display.

xquery version "3.0";

module namespace app="http://digitalhumanities.princeton.edu/mep/templates";

import module namespace templates="http://exist-db.org/xquery/templates" ;
import module namespace config="http://digitalhumanities.princeton.edu/mep/config" at "config.xqm";
declare namespace tei="http://www.tei-c.org/ns/1.0";

declare
    %templates:wrap
function app:sex-distribution($node as node(), $model as map(*))
{
    let $expats := collection($config:data-root)//tei:listPerson[@xml:id = 'expats']
    let $identified-as-female :=
       $expats/tei:person[tei:sex/@value = $config:female-key]
    let $identified-as-male :=
        $expats/tei:person[tei:sex/@value = $config:male-key]
    let $unidentified :=
        $expats/tei:person[empty(tei:sex)]
return

Sex Distribution

                Identified Sex
                Number of Individuals

                Identified as Female
                { count($identified-as-female) }

                Identified as Male
                { count($identified-as-male) }

                Unidentified Sex
                { count($unidentified) }

};

declare %templates:wrap function app:national-distribution($node as node(), $model as map(*))
{
    let $expats := collection($config:data-root)//tei:listPerson[@xml:id = 'expats']
    let $nationalities := $expats//tei:nationality
    return

Nationality Distribution

                    Nationality Key
                    Number of instances in database

 {
        for $key in distinct-values($nationalities/@key)
        let $label := xs:string($key)
        let $count := count($nationalities[@key=$key])
        order by $count descending
        return

            { $label }
            { $count }

        }

};

declare %templates:wrap function app:cards($node as node(), $model as map(*))
{
    let $cards := collection($config:data-root)//tei:TEI[tei:teiHeader//tei:classCode='300026802']
    return map { "cards" : $cards }
};

declare %templates:wrap function app:current-card($node as node(), $model as map(*), $subscriber as xs:string?)
{
    let $key  :=
        if ($subscriber) then "#"||$subscriber
        else ""

    let $card :=
        if ($key) then
            collection($config:data-root)//tei:TEI[tei:teiHeader//tei:particDesc/tei:person/@ana = $key]
        else ()
    return
        if ($card) then
            map { "current-card" : $card }
        else ()
};

declare %templates:wrap function app:cardholders($node as node(), $model as map(*))
{

 {
    for $card in $model('cards')
    let $person := $card/tei:teiHeader//tei:particDesc/tei:person[@role = 'cardholder']
    let $label  := xs:string($person[1]/tei:persName)
    let $key    := $person[1]/@ana
    let $key    := fn:replace($key, "^#?(.*)$", "$1")
    let $link   := 'library.html?subscriber=' || $key
    order by tokenize($label, ' ')[last()]
    return

{ $label }

    }

};

declare function app:view-card($node as node(), $model as map(*))
{
    let $card := $model('current-card')
    let $xsl  := doc($config:app-root || "/resources/xsl/cardview.xsl")

    return
        if ($card) then
            transform:transform($card, $xsl, ())
        else ()
};

declare %templates:wrap function app:expats($node as node(), $model as map(*))
{
    let $expats := collection($config:data-root)//tei:listPerson[@xml:id='expats']/tei:person
    return map { "expats" : $expats }
};

declare %templates:wrap function app:expats-list($node as node(), $model as map(*))
{
    let $expats := $model('expats')
    return

{
            for $person in $expats
            let $surname  := $person/tei:persName[1]/tei:surname[1]
            let $forename := $person/tei:persName[1]/tei:forename[1]
            let $lifespan := $person/tei:birth || '--' || $person/tei:death
            let $key      := $person/@xml:id
            let $link     := "expats.html?person=" || $key
            order by $surname
            return

                    { string-join(($forename, $surname), ' ') }

        }

};

declare %templates:wrap function app:expat($node as node(), $model as map(*), $person as xs:string?)
{
    let $expat :=
        if ($person) then
            collection($config:data-root)//tei:listPerson[@xml:id='expats']/tei:person[@xml:id = $person]
        else ()

        return map { 'current-expat' : $expat }
};

declare %templates:wrap function app:expat-info($node as node(), $model as map(*))
{
    let $expat := $model('current-expat')
    return
        if ($expat) then

{
                    let $namestring := $expat/tei:persName/tei:surname[1] || ', ' || $expat/tei:persName/tei:forename[1]
                    return $namestring
                }

viaf

{
                    let $viafnum := $expat/tei:idno[@type='viaf']
                    let $link    := 'http://viaf.org/viaf/' || $viafnum
                    return
                    { $viafnum }
                }

birth

{ $expat/tei:birth }

death

{ $expat/tei:death }

identified sex

{
                    let $sex-key := $expat/tei:sex/@value
                    return
                        if ($sex-key = $config:female-key) then "female"
                        else if ($sex-key = $config:male-key) then "male"
                        else "unestablished"
                }

identified nationality

                    {
                        for $nationality in $expat/tei:nationality
                        return
{ xs:string($nationality/@key) }

                    }

known addresses

{
                    let $residences := $expat/tei:residence
                    return

                        {
                            for $residence in $residences return
{ $residence }

                        }

                }

books on card

{
                        let $key  :=
                            if ($expat) then "#"||$expat/@xml:id
                            else ""

                        let $card :=
                            if ($key) then
                            collection($config:data-root)//tei:TEI[tei:teiHeader//tei:particDesc/tei:person/@ana = $key]
                            else ()

                        let $bibls :=
                            if ($card) then
                                $card//tei:bibl
                            else ()

                        let $titles :=
                            for $bibl in $bibls
                            return
                                if ($bibl/tei:title) then xs:string($bibl/tei:title)
                                else xs:string($bibl)
                        return

                                {
                                    for $title in distinct-values($titles)
                                    return
{ $title }

                                }

                }

        else ()
};

xquery version "3.0";

module namespace app="http://digitalhumanities.princeton.edu/mep/templates";

import module namespace templates="http://exist-db.org/xquery/templates" ;
import module namespace config="http://digitalhumanities.princeton.edu/mep/config" at "config.xqm";
declare namespace tei="http://www.tei-c.org/ns/1.0";

declare
    %templates:wrap
function app:sex-distribution($node as node(), $model as map(*))
{
    let $expats := collection($config:data-root)//tei:listPerson[@xml:id = 'expats']
    let $identified-as-female :=
       $expats/tei:person[tei:sex/@value = $config:female-key]
    let $identified-as-male :=
        $expats/tei:person[tei:sex/@value = $config:male-key]
    let $unidentified :=
        $expats/tei:person[empty(tei:sex)]
return

Sex Distribution

                Identified Sex
                Number of Individuals

                Identified as Female
                { count($identified-as-female) }

                Identified as Male
                { count($identified-as-male) }

                Unidentified Sex
                { count($unidentified) }

};

declare %templates:wrap function app:national-distribution($node as node(), $model as map(*))
{
    let $expats := collection($config:data-root)//tei:listPerson[@xml:id = 'expats']
    let $nationalities := $expats//tei:nationality
    return

Nationality Distribution

                    Nationality Key
                    Number of instances in database

 {
        for $key in distinct-values($nationalities/@key)
        let $label := xs:string($key)
        let $count := count($nationalities[@key=$key])
        order by $count descending
        return

            { $label }
            { $count }

        }

};

declare %templates:wrap function app:cards($node as node(), $model as map(*))
{
    let $cards := collection($config:data-root)//tei:TEI[tei:teiHeader//tei:classCode='300026802']
    return map { "cards" : $cards }
};

declare %templates:wrap function app:current-card($node as node(), $model as map(*), $subscriber as xs:string?)
{
    let $key  :=
        if ($subscriber) then "#"||$subscriber
        else ""

    let $card :=
        if ($key) then
            collection($config:data-root)//tei:TEI[tei:teiHeader//tei:particDesc/tei:person/@ana = $key]
        else ()
    return
        if ($card) then
            map { "current-card" : $card }
        else ()
};

declare %templates:wrap function app:cardholders($node as node(), $model as map(*))
{

 {
    for $card in $model('cards')
    let $person := $card/tei:teiHeader//tei:particDesc/tei:person[@role = 'cardholder']
    let $label  := xs:string($person[1]/tei:persName)
    let $key    := $person[1]/@ana
    let $key    := fn:replace($key, "^#?(.*)$", "$1")
    let $link   := 'library.html?subscriber=' || $key
    order by tokenize($label, ' ')[last()]
    return

{ $label }

    }

};

declare function app:view-card($node as node(), $model as map(*))
{
    let $card := $model('current-card')
    let $xsl  := doc($config:app-root || "/resources/xsl/cardview.xsl")

    return
        if ($card) then
            transform:transform($card, $xsl, ())
        else ()
};

declare %templates:wrap function app:expats($node as node(), $model as map(*))
{
    let $expats := collection($config:data-root)//tei:listPerson[@xml:id='expats']/tei:person
    return map { "expats" : $expats }
};

declare %templates:wrap function app:expats-list($node as node(), $model as map(*))
{
    let $expats := $model('expats')
    return

{
            for $person in $expats
            let $surname  := $person/tei:persName[1]/tei:surname[1]
            let $forename := $person/tei:persName[1]/tei:forename[1]
            let $lifespan := $person/tei:birth || '--' || $person/tei:death
            let $key      := $person/@xml:id
            let $link     := "expats.html?person=" || $key
            order by $surname
            return

                    { string-join(($forename, $surname), ' ') }

        }

};

declare %templates:wrap function app:expat($node as node(), $model as map(*), $person as xs:string?)
{
    let $expat :=
        if ($person) then
            collection($config:data-root)//tei:listPerson[@xml:id='expats']/tei:person[@xml:id = $person]
        else ()

        return map { 'current-expat' : $expat }
};

declare %templates:wrap function app:expat-info($node as node(), $model as map(*))
{
    let $expat := $model('current-expat')
    return

{
                    let $namestring := $expat/tei:persName/tei:surname[1] || ', ' || $expat/tei:persName/tei:forename[1]
                    return $namestring
                }

viaf

{
                    let $viafnum := $expat/tei:idno[@type='viaf']
                    let $link    := 'http://viaf.org/viaf/' || $viafnum
                    return
                    { $viafnum }
                }

birth

{ $expat/tei:birth }

death

{ $expat/tei:death }

identified sex

{
                    let $sex-key := $expat/tei:sex/@value
                    return
                        if ($sex-key = $config:female-key) then "female"
                        else if ($sex-key = $config:male-key) then "male"
                        else "unestablished"
                }

identified nationality

                    {
                        for $nationality in $expat/tei:nationality
                        return
{ xs:string($nationality/@key) }

                    }

known addresses

{
                    let $residences := $expat/tei:residence
                    return

                        {
                            for $residence in $residences return
{ $residence }

                        }

                }

books on card

{
                        let $key  :=
                            if ($expat) then "#"||$expat/@xml:id
                            else ""

                        let $card :=
                            if ($key) then
                            collection($config:data-root)//tei:TEI[tei:teiHeader//tei:particDesc/tei:person/@ana = $key]
                            else ()

                        let $bibls :=
                            if ($card) then
                                $card//tei:bibl
                            else ()

                        let $titles :=
                            for $bibl in $bibls
                            return
                                if ($bibl/tei:title) then xs:string($bibl/tei:title)
                                else xs:string($bibl)
                        return

                                {
                                    for $title in distinct-values($titles)
                                    return
{ $title }

                                }

                }

};


Add $next-match example.

Add $next-match example.

xquery version "3.0";

(:
 : Copyright (c) 2011 John Snelson
 :
 : 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.
 :)

import module namespace tfm = "http://snelson.org.uk/functions/transform" at "../transform.xq";

declare %tfm:rule("default","@*")
function local:default1($mode, $node)
{
  ()
};

declare %tfm:rule("default","para")
function local:default2($mode, $node)
{

{ $mode($node/(@*|node())) }

};

declare %tfm:rule("default","section/title")
function local:default3($mode, $node)
{

{ $mode($node/(@*|node())) }

};

declare %tfm:rule("default","article/title")
function local:default4($mode, $node)
{

{ $mode($node/(@*|node())) }

};

declare %tfm:rule("default","section")
function local:default5($mode, $node)
{

{ $mode($node/(@*|node())) }

};

declare %tfm:rule("default","article")
function local:default6($mode, $node)
{

    <title>{ $node/*:title/string() }</title>
    { $mode($node/(@*|node())) }

};

declare %tfm:rule("extend","section/title/text()")
function local:extend1($mode, $node)
{
  "__", $node, "__"
};

declare %tfm:rule("extend","article/title")
function local:extend1($mode, $node, $next-match)
{

, $next-match()
};

declare %tfm:rule("extend","@id")
function local:extend2($mode, $node)
{
  $node
};

declare %tfm:rule("extend","link")
function local:extend3($mode, $node)
{
  { $mode($node/(@*|node())) }
};

let $mode := tfm:named-mode("default")
let $emode := tfm:named-extend-mode($mode,"extend")
return $emode(

    <title>Lala</title>

      <title>One</title>
      <para>Once upon a <link ref="two">time</link></para>

      <title>Two</title>
      <para>There lived...</para>

)

xquery version "3.0";

(:
 : Copyright (c) 2011 John Snelson
 :
 : 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.
 :)

import module namespace tfm = "http://snelson.org.uk/functions/transform" at "../transform.xq";

declare %tfm:rule("default","@*")
function local:default1($mode, $node)
{
  ()
};

declare %tfm:rule("default","para")
function local:default2($mode, $node)
{

{ $mode($node/(@*|node())) }

};

declare %tfm:rule("default","section/title")
function local:default3($mode, $node)
{

{ $mode($node/(@*|node())) }

};

declare %tfm:rule("default","article/title")
function local:default4($mode, $node)
{

{ $mode($node/(@*|node())) }

};

declare %tfm:rule("default","section")
function local:default5($mode, $node)
{

{ $mode($node/(@*|node())) }

};

declare %tfm:rule("default","article")
function local:default6($mode, $node)
{

    <title>{ $node/*:title/string() }</title>
    { $mode($node/(@*|node())) }

};

declare %tfm:rule("extend","section/title/text()")
function local:extend1($mode, $node)
{
  "__", $node, "__"
};

declare %tfm:rule("extend","@id")
function local:extend2($mode, $node)
{
  $node
};

declare %tfm:rule("extend","link")
function local:extend3($mode, $node)
{
  { $mode($node/(@*|node())) }
};

let $mode := tfm:named-mode("default")
let $emode := tfm:named-extend-mode($mode,"extend")
return $emode(

    <title>Lala</title>

      <title>One</title>
      <para>Once upon a <link ref="two">time</link></para>

      <title>Two</title>
      <para>There lived...</para>

)


Updated the query.

Updated the query.

git-svn-id: 577f56b988395b4c4a087ab41a6af3288056d860@1543236 13f79535-47bb-0310-9956-ffa450edef68

(: XQuery Aggregate Query :)
(: Find the total precipitation recorded :)
fn:sum(
    let $collection := "/tmp/test/1.0_partition_ghcnd_gsn_xml_gz/sensors"
    for $r in collection($collection)/dataCollection/data
    where $r/dataType eq "PRCP"
    return $r/value
)

(: XQuery Aggregate Query :)
(: Find the total precipitation recorded :)
let $collection := "/tmp/test/1.0_partition_ghcnd_gsn_xml_gz/sensors"
return fn:sum(
    for $r in collection($collection)/dataCollection/data
    where $r/dataType eq "PRCP"
    return $r/value
)


added update/create/delete methods for top-level provider name details

(:~
: This is a module contatining  stored queries for a Care Services Discovery compliant Provider registry
: @version 1.0
: @see https://github.com/his-interop/openinfoman @see http://ihe.net
:
:)
module namespace csd_prsq = "https://github.com/his-interop/openinfoman-pr/csd_prsq";

import module namespace csd = "urn:ihe:iti:csd:2013" at "csd_base_library.xqm";
declare default element  namespace   "urn:ihe:iti:csd:2013";

declare variable $csd_prsq:stored_functions :=
(
    <function uuid='fcbab300-6270-11e3-bd76-0002a5d5c51b'
              method='csd_prsq:oid_search_by_id'
 	     content-type='text/xml; charset=utf-8'
	     />,
    <function uuid='8a5df595-51ec-46e6-8a92-7db3c2484ee8'
              method='csd_prsq:get_oids'
 	     content-type='text/xml; charset=utf-8'
	     />,
	     (:Methods for Names:)
    <function uuid='e3cd7f80-7edb-11e3-baa7-0800200c9a66'
              method='csd_prsq:indices_name'
 	      content-type='text/xml; charset=utf-8'
	     />,
    <function uuid='d251f150-7edb-11e3-baa7-0800200c9a66'
              method='csd_prsq:read_name'
 	     content-type='text/xml; charset=utf-8'
	     />,
    <function uuid='4808be30-7f84-11e3-baa7-0800200c9a66'
              method='csd_prsq:delete_name'
 	     content-type='text/xml; charset=utf-8'
	     updating='1'
	     />,
    <function uuid='8c8a2080-7f84-11e3-baa7-0800200c9a66'
              method='csd_prsq:create_name'
 	     content-type='text/xml; charset=utf-8'
	     updating='1'

	     />,
    <function uuid='866455e0-7f84-11e3-baa7-0800200c9a66'
              method='csd_prsq:update_name'
 	     content-type='text/xml; charset=utf-8'
	      updating='1'

	     />

);

(:Utility methods:)
declare function csd_prsq:wrap_providers($providers)
{
<CSD xmlns:csd="urn:ihe:iti:csd:2013"  >
  <organizationDirectory/>
  <serviceDirectory/>
  <facilityDirectory/>
  <providerDirectory>
  {$providers}
  </providerDirectory>
</CSD>

};

declare updating function csd_prsq:wrap_updating_providers($providers)
{
  db:output(
    (
    <rest:response>
      <http:response status="200" >
	<http:header name="Content-Type" value="text/xml"/>
      </http:response>
      </rest:response>,
      csd_prsq:wrap_providers($providers)
      )
     )
};

(:Top-Level Provider  methods:)
declare function csd_prsq:get_oids($requestParams, $doc) as element()
{
  let $provs0 := if (exists($requestParams/id)) then csd:filter_by_primary_id($doc/CSD/providerDirectory/*,$requestParams/id) else $doc/CSD/providerDirectory/*
  let $provs1 := if (exists($requestParams/otherID)) then csd:filter_by_other_id($provs0,$requestParams/otherID) else $provs0
  let $provs2 := if (exists($requestParams/commonName)) then csd:filter_by_common_name($provs1,$requestParams/commonName) else $provs1
  let $provs3 := if (exists($requestParams/type)) then csd:filter_by_coded_type($provs2,$requestParams/type)    else $provs2
  let $provs4 := if (exists($requestParams/address/addressLine)) then csd:filter_by_address($provs3, $requestParams/address/addressLine) else $provs3
  let $provs5 := if (exists($requestParams/record)) then csd:filter_by_record($provs4,$requestParams/record) else $provs4
  let $provs6 := if (exists($requestParams/start) and exists($requestParams/max)) then csd:limit_items($provs5,$requestParams/start,$requestParams/max) else $provs5
  let $provs7 := for $oid in $provs6/@oid
   return <provider oid="{$oid}"/>

  return csd_prsq:wrap_providers($provs7)
};

declare function csd_prsq:oid_search_by_id($requestParams, $doc) as element()
{
  let $provs0 := if (exists($requestParams/otherID)) then csd:filter_by_other_id($doc/CSD/providerDirectory/*,$requestParams/otherID) else ()
  let $provs1 := if (exists($requestParams/start) and exists($requestParams/max)) then csd:limit_items($provs0,$requestParams/start,$requestParams/max) else $provs0
  let $provs2:= for $oid in $provs1/@oid
   return <provider oid="{$oid}"/>

  return csd_prsq:wrap_providers($provs2)
};

(:Methods for Names:)
declare function csd_prsq:indices_name($requestParams, $doc) as element()
{
  let $provs0 :=
    if (exists($requestParams/id/@oid)) then
      csd:filter_by_primary_id($doc/CSD/providerDirectory/*,$requestParams/id)
    else ($doc/CSD/providerDirectory/*)
  let $provs1:=
      for $provider in  $provs0
      return
      <provider oid="{$provider/@oid}">
	<demographic>
	  {
	    for $name at $pos  in  $provider/demographic/name
	    return <name position="{$pos}"/>
	  }
	</demographic>
    </provider>

    return csd_prsq:wrap_providers($provs1)
};

declare function csd_prsq:read_name($requestParams, $doc) as element()
{

let $provs0 := if (exists($requestParams/name/@position)) then $doc/CSD/providerDirectory/*  else ()
let $provs1 := if (exists($requestParams/id/@oid)) then csd:filter_by_primary_id($provs0,$requestParams/id) else ()
let $provs2 :=
  if (count($provs1) = 1)
    then
    let $provider :=  $provs1[1]
    return
    <provider oid="{$provider/@oid}">
      <demographic>
	{
	  if (exists($requestParams/name) and exists($requestParams/name/@position)) then
	    for $name in $provider/demographic/name[position() = $requestParams/name/@position]
	    return <name position="{$requestParams/name/@position}">{$name/*}</name>
	  else
	    ()
	}
      </demographic>
      {$provider/record}
    </provider>
  else ()

return csd_prsq:wrap_providers($provs2)
};

declare updating function csd_prsq:create_name($requestParams, $doc)
{

let $provs0 := if (exists($requestParams/id/@oid)) then	csd:filter_by_primary_id($doc/CSD/providerDirectory/*,$requestParams/id) else ()
let $provs1 := if (count($provs0) = 1) then $provs0 else ()
let $provs2 := if (exists($requestParams/name))  then $provs1 else ()
return
  if ( count($provs2) = 1 )
    then
    let $provider:= $provs2[1]
    let $name := <name/>
    let $position := count($provider/demographic/name) +1
    let $provs3:=
    <provider oid="{$provider/@oid}">
      <demographic>
	<name position="{$position}"/>
      </demographic>
    </provider>
    return (
      insert node $name into $provider/demographic,
      csd_prsq:update_name_parts($name,$requestParams/name),
      csd_prsq:wrap_updating_providers($provs3)
    )
  else  csd_prsq:wrap_updating_providers(())

};

declare updating function csd_prsq:update_name($requestParams, $doc)
{
let $provs0 := if (exists($requestParams/name/@position)) then $doc/CSD/providerDirectory/*  else ()
let $provs1 := if (exists($requestParams/id/@oid)) then csd:filter_by_primary_id($provs0,$requestParams/id) else ()
let $name := $provs1[1]/demographic/name[position() = $requestParams/name/@position]
return
  if (count($provs1) = 1 and exists($name))
    then
    let $provs2 :=
    <provider oid="{$provs1[1]/@oid}">
      <demographic>
	<name position="{$requestParams/name/@position}"/>
      </demographic>
    </provider>
    return
      (
	csd_prsq:update_name_parts($name,$requestParams/name),
	csd_prsq:wrap_updating_providers($provs2)
     )
  else 	csd_prsq:wrap_updating_providers(())

};

declare updating function csd_prsq:update_name_parts($old,$new)
{
  (
    if (exists($new/honorific))
      then
      (if (exists($old/honorific)) then (delete node $old/honoroific) else (),
      insert node $new/honorofic into $old)
    else (),
    if (exists($new/surname))
      then
      (if (exists($old/surname)) then (delete node $old/surname) else (),
      insert node $new/surname into $old)
    else (),
    if (exists($new/forename)) then
      (if (exists($old/forename)) then (delete node $old/forename) else (),
      insert node $new/forename into $old)
    else (),
      if (exists($new/suffix)) then
	(if (exists($old/suffix)) then (delete node $old/suffix) else (),
	insert node $new/suffix into $old)
      else ()
  )
};

declare updating function csd_prsq:delete_name($requestParams, $doc)
{
  if (exists($requestParams/name/@position))
    then
    let $providers := if (exists($requestParams/id/@oid)) then csd:filter_by_primary_id($doc/CSD/providerDirectory/*,$requestParams/id) else ()
    return
      if ( count($providers) = 1 )
	then
	let  $name :=  $providers[1]/demographic/name[position() = $requestParams/name/@position]
	return if (exists($name)) then (delete node $name) else ()
      else  ()
    else ()
};

(:~
: This is a module contatining  stored queries for a Care Services Discovery compliant Provider registry
: @version 1.0
: @see https://github.com/his-interop/openinfoman @see http://ihe.net
:
:)
module namespace csd_prsq = "https://github.com/his-interop/openinfoman-pr/csd_prsq";

import module namespace csd = "urn:ihe:iti:csd:2013" at "csd_base_library.xqm";
declare default element  namespace   "urn:ihe:iti:csd:2013";

declare variable $csd_prsq:stored_functions :=
(
    <function uuid='fcbab300-6270-11e3-bd76-0002a5d5c51b'
              method='csd_prsq:oid_search_by_id'
 	     content-type='text/xml; charset=utf-8'
	     />,
    <function uuid='8a5df595-51ec-46e6-8a92-7db3c2484ee8'
              method='csd_prsq:get_oids'
 	     content-type='text/xml; charset=utf-8'
	     />,
    <function uuid='e3cd7f80-7edb-11e3-baa7-0800200c9a66'
              method='csd_prsq:get_name_indices'
 	     content-type='text/xml; charset=utf-8'
	     />,
    <function uuid='d251f150-7edb-11e3-baa7-0800200c9a66'
              method='csd_prsq:get_name'
 	     content-type='text/xml; charset=utf-8'
	     />

);

declare function csd_prsq:get_oids($requestParams, $doc) as element()
{
<CSD xmlns:csd="urn:ihe:iti:csd:2013"  >
  <organizationDirectory/>
  <serviceDirectory/>
  <facilityDirectory/>
  <providerDirectory>
    {
      let $provs0 := if (exists($requestParams/id)) then csd:filter_by_primary_id($doc/CSD/providerDirectory/*,$requestParams/id) else $doc/CSD/providerDirectory/*
      let $provs1 := if (exists($requestParams/otherID)) then csd:filter_by_other_id($provs0,$requestParams/otherID) else $provs0
      let $provs2 := if (exists($requestParams/commonName)) then csd:filter_by_common_name($provs1,$requestParams/commonName) else $provs1
      let $provs3 := if (exists($requestParams/type)) then csd:filter_by_coded_type($provs2,$requestParams/type)    else $provs2
      let $provs4 := if (exists($requestParams/address/addressLine)) then csd:filter_by_address($provs3, $requestParams/address/addressLine) else $provs3
      let $provs5 := if (exists($requestParams/record)) then csd:filter_by_record($provs4,$requestParams/record) else $provs4
      let $provs6 := if (exists($requestParams/start) and exists($requestParams/max)) then csd:limit_items($provs5,$requestParams/start,$requestParams/max) else $provs5
      for $oid in $provs6/@oid
        return <provider oid="{$oid}"/>
    }
  </providerDirectory>
</CSD>
};

declare function csd_prsq:get_name($requestParams, $doc) as element()
{
<CSD xmlns:csd="urn:ihe:iti:csd:2013"  >
  <organizationDirectory/>
  <serviceDirectory/>
  <facilityDirectory/>
  <providerDirectory>
    {
      for $provider in  if (exists($requestParams/id)) then csd:filter_by_primary_id($doc/CSD/providerDirectory/*,$requestParams/id) else ()
	return
	<provider oid="{$provider/@oid}">
	  <demographic>
	  {
	    if (exists($requestParams/nameIndex)) then
	      for $name in $provider/demographic/name[position() = $requestParams/nameIndex]
	      return <name id="{$requestParams/nameIndex}">{$name/*}</name>
            else
	      ()
	  }
	  </demographic>
	  {$provider/record}
	</provider>
    }
  </providerDirectory>
</CSD>

};

declare function csd_prsq:get_name_indices($requestParams, $doc) as element()
{
<CSD xmlns:csd="urn:ihe:iti:csd:2013"  >
  <organizationDirectory/>
  <serviceDirectory/>
  <facilityDirectory/>
  <providerDirectory>
    {
      let $providers :=
	if (exists($requestParams/id)) then
	  csd:filter_by_primary_id($doc/CSD/providerDirectory/*,$requestParams/id)
	else ($doc/CSD/providerDirectory/*)
      for $provider in  $providers
	return
	<provider oid="{$provider/@oid}">
	  <demographic>
	  {
	    for $name at $pos  in  $provider/demographic/name
	    return <name id="{$pos}"/>
	  }
	  </demographic>
	</provider>
    }
  </providerDirectory>
</CSD>

};

declare function csd_prsq:oid_search_by_id($requestParams, $doc) as element()
{
<CSD xmlns:csd="urn:ihe:iti:csd:2013"  >
  <organizationDirectory/>
  <serviceDirectory/>
  <facilityDirectory/>
  <providerDirectory>
    {
      let $provs0 := if (exists($requestParams/otherID)) then csd:filter_by_other_id($doc/CSD/providerDirectory/*,$requestParams/otherID) else ()
      let $provs1 := if (exists($requestParams/start) and exists($requestParams/max)) then csd:limit_items($provs0,$requestParams/start,$requestParams/max) else $provs0
      for $oid in $provs1/@oid
       return <provider oid="{$oid}"/>
    }
  </providerDirectory>
</CSD>

};


[ignore] corrected wrong atom feed urls in the news section. Port of rev 8793

svn path=/branches/eXist-stable-1.2/; revision=9135

xquery version "1.0";

declare namespace atom="http://www.w3.org/2005/Atom";

declare variable $atom:server := "http://atomic.exist-db.org";
declare variable $atom:uri := concat($atom:server, "/atom/summary/wiki/blogs/eXist/");

declare function atom:format-entry($feed as element()) {

    {
        for $entry in $feed//atom:entry
        let $link := $entry/atom:link[@rel = 'alternate'][@type = 'text/html']/@href
        return

                    {substring($entry/atom:published, 1, 10)}

                    {$entry/atom:title/text()}

    }

};

let $uri := xs:anyURI($atom:uri)
let $response := doc($uri)
return
    atom:format-entry($response/atom:feed)


Update BaseX Math module. I'm not sure if these changes are correct: since the BaseX `math:` namespace is the w3 implementation, I attempted to add the BaseX "Additional Functions" in that module.

xquery version "3.0" encoding "UTF-8";
(:~
 : XPath and XQuery Functions and Operators: Trigonometric and exponential functions
 :
 : @see https://www.w3.org/TR/2014/REC-xpath-functions-30-20140408/#trigonometry
 :
 : This documentation includes material copied from or derived from the XPath and
 : XQuery Functions and Operators 3.0 specification. Copyright © 2017 W3C®
 : (MIT, ERCIM, Keio, Beihang).
 :)
module namespace math = "http://www.w3.org/2005/xpath-functions/math";

declare namespace a = "http://reecedunn.co.uk/xquery/annotations";
declare namespace o = "http://reecedunn.co.uk/xquery/options";

declare option o:requires "xpath-functions/3.0";

declare %a:since("xpath-functions", "3.0-20140408") function math:acos($arg as xs:double?) as xs:double? external;
declare %a:since("xpath-functions", "3.0-20140408") function math:asin($arg as xs:double?) as xs:double? external;
declare %a:since("xpath-functions", "3.0-20140408") function math:atan($arg as xs:double?) as xs:double? external;
declare %a:since("xpath-functions", "3.0-20140408") function math:atan2($y as xs:double, $x as xs:double) as xs:double external;
declare %a:since("xpath-functions", "3.0-20140408") function math:cos($θ as xs:double?) as xs:double? external;
declare %a:since("xpath-functions", "3.0-20140408") function math:exp($arg as xs:double?) as xs:double? external;
declare %a:since("xpath-functions", "3.0-20140408") function math:exp10($arg as xs:double?) as xs:double? external;
declare %a:since("xpath-functions", "3.0-20140408") function math:log($arg as xs:double?) as xs:double? external;
declare %a:since("xpath-functions", "3.0-20140408") function math:log10($arg as xs:double?) as xs:double? external;
declare %a:since("xpath-functions", "3.0-20140408") function math:pi() as xs:double external;
declare %a:since("xpath-functions", "3.0-20140408") function math:pow($x as xs:double?, $y as xs:numeric) as xs:double? external;
declare %a:since("xpath-functions", "3.0-20140408") function math:sin($θ as xs:double?) as xs:double? external;
declare %a:since("xpath-functions", "3.0-20140408") function math:sqrt($arg as xs:double?) as xs:double? external;
declare %a:since("xpath-functions", "3.0-20140408") function math:tan($θ as xs:double?) as xs:double? external;
declare %a:since("basex", "7.0") function math:e() as xs:double external;
declare %a:since("basex", "7.0") function math:sinh($arg as xs:double?) as xs:double? external;
declare %a:since("basex", "7.0") function math:cosh($arg as xs:double?) as xs:double? external;
declare %a:since("basex", "7.0") function math:tanh($arg as xs:double?) as xs:double? external;
declare %a:restrict-until("$string", "basex", "9.1", "xs:string")
        %a:since("basex", "7.3") function math:crc32($string as xs:string?) as xs:hexBinary? external;
declare %a:since("basex", "7.3") %a:until("basex", "7.5") %a:see-also("basex", "7.5", "random:uuid") function math:uuid() external;
declare %a:since("basex", "7.0") %a:until("basex", "7.5") %a:see-also("basex", "7.5", "random:double") function math:random() external;