rewrote courses transformation to use functions as arguments

declare function local:transform($nodefilter as function(element()) as xs:boolean, $nodeadd as function(element()) as item()*, $input as item()*) as item()* {
for $node in $input
   return
      typeswitch($node)
        case element()
         return
          if ($nodefilter($node)) then
              element {name($node)} {
                $nodeadd($node),
                for $att in $node/@*
                      return attribute {name($att)} {$att}
                ,
                for $child in $node
                   return local:transform($nodefilter, $nodeadd, $child/node())

              }
          else ()
        default return $node
};

let $f := function($node as element()) as xs:boolean {name($node) != 'name'},
	$g := function($node as element()) as item()* {if (name($node) = 'courses') then
                    for $na in distinct-values($node/course/taken_by/student/name/text()) return element {'newET0'} {  for $nu in distinct-values($node/course/taken_by/student[name/text() = $na]/@sno) return
                  element {'newET00'} {attribute {'sno'} {$nu}},
                  element {'name'} {$na}
                  }
                else ()}
  return
	local:transform($f, $g, doc("test.xml")/courses)

declare function local:transform($input as item()*) as item()* {
for $node in $input
   return
      typeswitch($node)
        case element()
         return
          if (name($node) != 'name') then
              element {name($node)} {
                if (name($node) = 'courses') then
                    for $na in distinct-values($node/course/taken_by/student/name/text()) return element {'newET0'} {  for $nu in distinct-values($node/course/taken_by/student[name/text() = $na]/@sno) return
                  element {'newET00'} {attribute {'sno'} {$nu}},
                  element {'name'} {$na}
                  }
                else (),
                for $att in $node/@*
                      return attribute {name($att)} {$att}
                ,
                for $child in $node
                   return local:transform($child/node())

              }
          else ()
        default return $node
};

local:transform(doc("test.xml")/courses)


updated map{}s to use : instead of := for webapp/storedFunctions

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

import module namespace csd_webconf =  "https://github.com/openhie/openinfoman/csd_webconf";
import module namespace csr_proc = "https://github.com/openhie/openinfoman/csr_proc";
declare   namespace   xforms = "http://www.w3.org/2002/xforms";
declare namespace xs = "http://www.w3.org/2001/XMLSchema";
declare   namespace   csd = "urn:ihe:iti:csd:2013";
declare default element  namespace   "urn:ihe:iti:csd:2013";
import module namespace random = "http://basex.org/modules/random";
import module namespace bin = "http://expath.org/ns/binary";
declare variable $page:xsl := "../resources/doc_careServiceFunctions.xsl";

declare
  %rest:path("/CSD/storedFunctions")
  %rest:GET
  %output:method("xhtml")
  function page:csr_list()
{
if (not (db:is-xml($csd_webconf:db,$csr_proc:stored_functions_doc))) then
  page:redirect(concat($csd_webconf:baseurl,"CSD/storedFunctions/init"))
else
  let $new := page:new_stored_function()
  let $reload:=

Registered Stored Queries

{count(csr_proc:stored_functions($csd_webconf:db))} Stored Functions

{count(csr_proc:stored_updating_functions($csd_webconf:db))} Stored Updating Functions

Reload stored functions from disk

    Export Documentation

Export Functions

Clear All Stored Functions

  let $list := page:function_list()
  return page:wrapper(($reload,$list),$new)
};

declare updating
  %rest:path("/CSD/storedFunctions/upload")
  %rest:consumes("application/xml", "text/xml", "multipart/form-data")
  %rest:form-param("upload","{$upload}")
  %rest:POST
  function page:upload($upload)
{
 for $name    in map:keys($upload)
 let $content := $upload($name)
 let $func := parse-xml(bin:decode-string($content, 'UTF-8'))
 return
   (
     csr_proc:load_stored_function($csd_webconf:db,$func/careServicesFunction)
     ,
   db:output(page:redirect(concat($csd_webconf:baseurl,"CSD/storedFunctions")))
  )

};

declare function page:new_stored_function()
{

Upload careServicesFunction Document

   <form method='post' action="/CSD/storedFunctions/upload"  enctype="multipart/form-data">
   Upload<input name='upload' type='file'/>
   <input type="submit" value="submit"/>
   </form>

Create New Stored Function

   <form method='post' action="/CSD/storedFunctions/create"  enctype="multipart/form-data">
     URN<input    size="42" name="urn" value="urn:uuid:{random:uuid()}"  readonly="readonly"/>

     Content Type<input    cols="80" name="content" value="text/html"/>

     Description<textarea  rows="20" cols="80" name="description" ></textarea>

     XQuery<textarea  rows="20" cols="80" name="query" ></textarea>

     <input type="submit" value="submit"/>
   </form>

};

declare  updating
  %rest:path("/CSD/storedFunctions/delete/{$urn}")
  function page:delete($urn)
  {
    (
      csr_proc:delete_stored_function($csd_webconf:db,$urn),
      db:output(page:redirect(concat($csd_webconf:baseurl,"CSD/storedFunctions")))
    )

};

declare
  %rest:path("/CSD/storedFunctions/download/{$urn}")
  function page:download($urn)
  {
    let $node := (
      csr_proc:get_function_definition($csd_webconf:db,$urn),
      csr_proc:get_updating_function_definition($csd_webconf:db,$urn)
    )[1]
    return $node

};

declare  updating
  %rest:path("/CSD/storedFunctions/clear")
  function page:clear()
  {
    (
      csr_proc:clear_stored_functions($csd_webconf:db),
      db:output(page:redirect(concat($csd_webconf:baseurl,"CSD/storedFunctions")))
    )

};

declare  updating
  %rest:path("/CSD/storedFunctions/create")
  %rest:consumes("application/xml", "text/xml", "multipart/form-data")
  %rest:POST
  %rest:form-param("query","{$query}")
  %rest:form-param("description","{$description}")
  %rest:form-param("content", "{$content}","application/xml")
  %rest:form-param("urn", "{$urn}")
  function page:create($urn,$query,$description,$content)
{
(  if ($urn) then
   let $func :=
   <careServicesFunction urn="{$urn}" content-type="{$content}">
     <description>{$description}</description>
     <definition>{$query}</definition>
   </careServicesFunction>
   return csr_proc:load_stored_function($csd_webconf:db,$func)
  else (),
    db:output(page:redirect(concat($csd_webconf:baseurl,"CSD/storedFunctions")))
)
};

declare updating
  %rest:path("/CSD/storedFunctions/init")
  %rest:GET
  function page:init()
{
(csr_proc:init($csd_webconf:db),
db:output(page:redirect(concat($csd_webconf:baseurl,"CSD/storedFunctions")))
)
};

declare updating
  %rest:path("/CSD/storedFunctions/reload")
  %rest:GET
  function page:reload()
{
(csr_proc:load_functions_from_files($csd_webconf:db),
db:output(page:redirect(concat($csd_webconf:baseurl,"CSD/storedFunctions")))
)
};

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

declare function page:display_function($function,$updating) {
  let  $urn := string($function/@urn)
  return
    {if ($updating) then  "(Updating) " else ()}
    URN: {string($urn)}

    Method:

{string($function/definition)}

    Content: {string(csr_proc:lookup_stored_content_type($csd_webconf:db,$urn)) }

    Description:
{$function/description}

    Instance:

{serialize($function/xforms:instance/careServicesRequest,map{'indent':'yes'})}

    {if (exists($function/@method)) then  ("Method: ",string($function/@method),
) else () }
    {if (exists($function/xs:schema)) then  ("Schema: ",string($function/xs:schema),
) else () }
    {if (count( $function/xforms:bind) > 0) then
    ("Bindings: ",

        {for $bind in $function/xforms:bind return
Node set: {string($bind/@nodeset)}
Type: {string($bind/@type)}
}

    ) else ()
    }

};

declare
  %rest:path("/CSD/storedFunctions/export_funcs")
  %rest:GET
  function page:export_funcs()
{
  <careServiceFunctions
    xmlns:xforms="http://www.w3.org/2002/xforms"
    xmlns:csd="urn:ihe:iti:csd:2013"
    xmlns:xi="http://www.w3.org/2001/XInclude"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:hfp="http://www.w3.org/2001/XMLSchema-hasFacetAndProperty"
     >
  {(
    csr_proc:stored_functions($csd_webconf:db)
    ,csr_proc:stored_updating_functions($csd_webconf:db)
   )}
 </careServiceFunctions>
};

declare
  %rest:path("/CSD/storedFunctions/export_doc")
  %rest:GET
  %output:method("xhtml")
  function page:export_doc()
{
  let $funcs :=
  <careServiceFunctions
    xmlns:xforms="http://www.w3.org/2002/xforms"
    xmlns:csd="urn:ihe:iti:csd:2013"
    xmlns:xi="http://www.w3.org/2001/XInclude"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:hfp="http://www.w3.org/2001/XMLSchema-hasFacetAndProperty"
     >
  {(
    csr_proc:stored_functions($csd_webconf:db)
    ,csr_proc:stored_updating_functions($csd_webconf:db)
   )}
 </careServiceFunctions>
(: return $funcs :)
 return xslt:transform($funcs,doc($page:xsl))
};

declare function page:function_list()  {

Function List

    {
      for $function in (csr_proc:stored_functions($csd_webconf:db),csr_proc:stored_updating_functions($csd_webconf:db))
      return

URN: {string($function/@urn)} {"  "}

	{substring(string($function/description),1,100)}
	{if (string-length(string($function/description)) > 100) then "..." else ()}

      View
      Download
      Delete

    }

    {
      (
	for $function in csr_proc:stored_functions($csd_webconf:db)
	return
{page:display_function($function,false())}

       ,
        for $function in csr_proc:stored_updating_functions($csd_webconf:db)
        return
{page:display_function($function,true())}

      )
    }

};

declare function page:wrapper($list,$new) {
  let $headers := (
    <link rel="stylesheet" type="text/css" media="screen"   href="{$csd_webconf:baseurl}static/bootstrap/js/tab.js"/>
   ,
  )
  let $content :=
    (

Available Functions

Upload Function

      ,

{$list}

{$new}

    )
  return csd_webconf:wrapper($content,$headers)
};

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

import module namespace csd_webconf =  "https://github.com/openhie/openinfoman/csd_webconf";
import module namespace csr_proc = "https://github.com/openhie/openinfoman/csr_proc";
declare   namespace   xforms = "http://www.w3.org/2002/xforms";
declare namespace xs = "http://www.w3.org/2001/XMLSchema";
declare   namespace   csd = "urn:ihe:iti:csd:2013";
declare default element  namespace   "urn:ihe:iti:csd:2013";
import module namespace random = "http://basex.org/modules/random";
import module namespace bin = "http://expath.org/ns/binary";
declare variable $page:xsl := "../resources/doc_careServiceFunctions.xsl";

declare
  %rest:path("/CSD/storedFunctions")
  %rest:GET
  %output:method("xhtml")
  function page:csr_list()
{
if (not (db:is-xml($csd_webconf:db,$csr_proc:stored_functions_doc))) then
  page:redirect(concat($csd_webconf:baseurl,"CSD/storedFunctions/init"))
else
  let $new := page:new_stored_function()
  let $reload:=

Registered Stored Queries

{count(csr_proc:stored_functions($csd_webconf:db))} Stored Functions

{count(csr_proc:stored_updating_functions($csd_webconf:db))} Stored Updating Functions

Reload stored functions from disk

    Export Documentation

Export Functions

Clear All Stored Functions

  let $list := page:function_list()
  return page:wrapper(($reload,$list),$new)
};

declare updating
  %rest:path("/CSD/storedFunctions/upload")
  %rest:consumes("application/xml", "text/xml", "multipart/form-data")
  %rest:form-param("upload","{$upload}")
  %rest:POST
  function page:upload($upload)
{
 for $name    in map:keys($upload)
 let $content := $upload($name)
 let $func := parse-xml(bin:decode-string($content, 'UTF-8'))
 return
   (
     csr_proc:load_stored_function($csd_webconf:db,$func/careServicesFunction)
     ,
   db:output(page:redirect(concat($csd_webconf:baseurl,"CSD/storedFunctions")))
  )

};

declare function page:new_stored_function()
{

Upload careServicesFunction Document

   <form method='post' action="/CSD/storedFunctions/upload"  enctype="multipart/form-data">
   Upload<input name='upload' type='file'/>
   <input type="submit" value="submit"/>
   </form>

Create New Stored Function

   <form method='post' action="/CSD/storedFunctions/create"  enctype="multipart/form-data">
     URN<input    size="42" name="urn" value="urn:uuid:{random:uuid()}"  readonly="readonly"/>

     Content Type<input    cols="80" name="content" value="text/html"/>

     Description<textarea  rows="20" cols="80" name="description" ></textarea>

     XQuery<textarea  rows="20" cols="80" name="query" ></textarea>

     <input type="submit" value="submit"/>
   </form>

};

declare  updating
  %rest:path("/CSD/storedFunctions/delete/{$urn}")
  function page:delete($urn)
  {
    (
      csr_proc:delete_stored_function($csd_webconf:db,$urn),
      db:output(page:redirect(concat($csd_webconf:baseurl,"CSD/storedFunctions")))
    )

};

declare
  %rest:path("/CSD/storedFunctions/download/{$urn}")
  function page:download($urn)
  {
    let $node := (
      csr_proc:get_function_definition($csd_webconf:db,$urn),
      csr_proc:get_updating_function_definition($csd_webconf:db,$urn)
    )[1]
    return $node

};

declare  updating
  %rest:path("/CSD/storedFunctions/clear")
  function page:clear()
  {
    (
      csr_proc:clear_stored_functions($csd_webconf:db),
      db:output(page:redirect(concat($csd_webconf:baseurl,"CSD/storedFunctions")))
    )

};

declare  updating
  %rest:path("/CSD/storedFunctions/create")
  %rest:consumes("application/xml", "text/xml", "multipart/form-data")
  %rest:POST
  %rest:form-param("query","{$query}")
  %rest:form-param("description","{$description}")
  %rest:form-param("content", "{$content}","application/xml")
  %rest:form-param("urn", "{$urn}")
  function page:create($urn,$query,$description,$content)
{
(  if ($urn) then
   let $func :=
   <careServicesFunction urn="{$urn}" content-type="{$content}">
     <description>{$description}</description>
     <definition>{$query}</definition>
   </careServicesFunction>
   return csr_proc:load_stored_function($csd_webconf:db,$func)
  else (),
    db:output(page:redirect(concat($csd_webconf:baseurl,"CSD/storedFunctions")))
)
};

declare updating
  %rest:path("/CSD/storedFunctions/init")
  %rest:GET
  function page:init()
{
(csr_proc:init($csd_webconf:db),
db:output(page:redirect(concat($csd_webconf:baseurl,"CSD/storedFunctions")))
)
};

declare updating
  %rest:path("/CSD/storedFunctions/reload")
  %rest:GET
  function page:reload()
{
(csr_proc:load_functions_from_files($csd_webconf:db),
db:output(page:redirect(concat($csd_webconf:baseurl,"CSD/storedFunctions")))
)
};

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

declare function page:display_function($function,$updating) {
  let  $urn := string($function/@urn)
  return
    {if ($updating) then  "(Updating) " else ()}
    URN: {string($urn)}

    Method:

{string($function/definition)}

    Content: {string(csr_proc:lookup_stored_content_type($csd_webconf:db,$urn)) }

    Description:
{$function/description}

    Instance:

{serialize($function/xforms:instance/careServicesRequest,map{'indent':='yes'})}

    {if (exists($function/@method)) then  ("Method: ",string($function/@method),
) else () }
    {if (exists($function/xs:schema)) then  ("Schema: ",string($function/xs:schema),
) else () }
    {if (count( $function/xforms:bind) > 0) then
    ("Bindings: ",

        {for $bind in $function/xforms:bind return
Node set: {string($bind/@nodeset)}
Type: {string($bind/@type)}
}

    ) else ()
    }

};

declare
  %rest:path("/CSD/storedFunctions/export_funcs")
  %rest:GET
  function page:export_funcs()
{
  <careServiceFunctions
    xmlns:xforms="http://www.w3.org/2002/xforms"
    xmlns:csd="urn:ihe:iti:csd:2013"
    xmlns:xi="http://www.w3.org/2001/XInclude"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:hfp="http://www.w3.org/2001/XMLSchema-hasFacetAndProperty"
     >
  {(
    csr_proc:stored_functions($csd_webconf:db)
    ,csr_proc:stored_updating_functions($csd_webconf:db)
   )}
 </careServiceFunctions>
};

declare
  %rest:path("/CSD/storedFunctions/export_doc")
  %rest:GET
  %output:method("xhtml")
  function page:export_doc()
{
  let $funcs :=
  <careServiceFunctions
    xmlns:xforms="http://www.w3.org/2002/xforms"
    xmlns:csd="urn:ihe:iti:csd:2013"
    xmlns:xi="http://www.w3.org/2001/XInclude"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:hfp="http://www.w3.org/2001/XMLSchema-hasFacetAndProperty"
     >
  {(
    csr_proc:stored_functions($csd_webconf:db)
    ,csr_proc:stored_updating_functions($csd_webconf:db)
   )}
 </careServiceFunctions>
(: return $funcs :)
 return xslt:transform($funcs,doc($page:xsl))
};

declare function page:function_list()  {

Function List

    {
      for $function in (csr_proc:stored_functions($csd_webconf:db),csr_proc:stored_updating_functions($csd_webconf:db))
      return

URN: {string($function/@urn)} {"  "}

	{substring(string($function/description),1,100)}
	{if (string-length(string($function/description)) > 100) then "..." else ()}

      View
      Download
      Delete

    }

    {
      (
	for $function in csr_proc:stored_functions($csd_webconf:db)
	return
{page:display_function($function,false())}

       ,
        for $function in csr_proc:stored_updating_functions($csd_webconf:db)
        return
{page:display_function($function,true())}

      )
    }

};

declare function page:wrapper($list,$new) {
  let $headers := (
    <link rel="stylesheet" type="text/css" media="screen"   href="{$csd_webconf:baseurl}static/bootstrap/js/tab.js"/>
   ,
  )
  let $content :=
    (

Available Functions

Upload Function

      ,

{$list}

{$new}

    )
  return csd_webconf:wrapper($content,$headers)
};


Fixed links to blog entries in news box.

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

xquery version "1.0";

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

import module namespace httpclient="http://exist-db.org/xquery/httpclient"
    at "java:org.exist.xquery.modules.httpclient.HTTPClientModule";
import module namespace json="http://www.json.org" at "resource:org/exist/xquery/lib/json.xq";

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 := httpclient:get($uri, false(), ())
return
    atom:format-entry($response/httpclient:body/atom:feed)

xquery version "1.0";

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

import module namespace httpclient="http://exist-db.org/xquery/httpclient"
    at "java:org.exist.xquery.modules.httpclient.HTTPClientModule";
import module namespace json="http://www.json.org" at "resource:org/exist/xquery/lib/json.xq";

declare variable $atom:uri := "http://atomic.exist-db.org/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 := httpclient:get($uri, false(), ())
return
    atom:format-entry($response/httpclient:body/atom:feed)


better comment for uuid function

better comment for uuid function

(:
 : Copyright 2006-2009 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.
:)

(:~
 : A module that provides several functions for generating (pseudo-)random
 : numbers and strings.
 :)
module namespace random = "http://www.zorba-xquery.com/modules/random";

(:~
 : This function returns a pseudo-random integer
 :
 : @return a pseudo-random integer
 :)
declare nondeterministic function random() as xs:integer external;

(:~
 : This function returns a pseudo-random integer
 : The function sets its argument as the seed for a new sequence
 : of pseudo-random integers to be returned.
 : These sequences are repeatable by calling this function with the
 : same seed value.
 :
 : @param $seed the seed value for this pseudo-random integer sequence
 : @return a pseudo-random integer
 :)
declare nondeterministic function random($seed as xs:integer) as xs:integer external;

(:~
 :  This function returns a uuid. Note, that the function is not stable,
 :  that is, it returns a different UUID everytime the function is invoked.
 :
 : @return the generated UUID
 :)
declare nondeterministic function uuid() as xs:string external;

(:
 : Copyright 2006-2009 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.
:)

(:~
 : A module that provides several functions for generating (pseudo-)random
 : numbers and strings.
 :)
module namespace random = "http://www.zorba-xquery.com/modules/random";

(:~
 : This function returns a pseudo-random integer
 :
 : @return a pseudo-random integer
 :)
declare nondeterministic function random() as xs:integer external;

(:~
 : This function returns a pseudo-random integer
 : The function sets its argument as the seed for a new sequence
 : of pseudo-random integers to be returned.
 : These sequences are repeatable by calling this function with the
 : same seed value.
 :
 : @param $seed the seed value for this pseudo-random integer sequence
 : @return a pseudo-random integer
 :)
declare nondeterministic function random($seed as xs:integer) as xs:integer external;

(:~
 :  This function does not generate a DCE 1.1 variant UUIDs.
 :
 : @return the generated UUID
 :)
declare nondeterministic function uuid() as xs:string external;


added sort by date to browse

added sort by date to browse

xquery version "3.0";

module namespace app="http://localhost:8080/exist/apps/xq-institute/templates";

import module namespace templates="http://exist-db.org/xquery/templates" ;
import module namespace config="http://localhost:8080/exist/apps/xq-institute/config" at "config.xqm";
declare namespace util="http://exist-db.org/xquery/util";
declare namespace tei="http://www.tei-c.org/ns/1.0";

declare variable $app:sort {request:get-parameter('sort', '')};
(:~
 : Browse using sort
 : Using user defined functions to modularize code
:)
declare %templates:wrap function app:browse-list-items($node as node(), $model as map(*)){
    for $play in collection($config:app-root || "/data/plays")
    let $title := $play//tei:titleStmt/tei:title/text()
    (: NOTE: construct a more robust function to run through a list of stop words using tokenize?:)
    let $sort-title := replace(replace($title,'^The ',''),'^A ','')
    let $date := $play//tei:witness[@xml:id = 'shakespeare-online'][1]/tei:date[1]/text()
    let $uri := base-uri($play)
    order by
        if($app:sort = 'date') then $date
        else $sort-title
    return
        app:display-title($title,$uri)
};

declare function app:display-title($title as xs:string?,$uri as xs:anyURI?){

            {$title}

            HTML | PDF | XML

};

(:~
 : Retrieve play xml transform with xsl for html output
 : @param $uri passes internal uri for play
 : @param $view view used for output
 :
:)
declare %templates:wrap function app:view-play-html($node as node(), $model as map(*)){
    let $uri := request:get-parameter('uri', '')
    let $rec := xmldb:document($uri)
    return transform:transform($rec, doc('../resources/xsl/teiHTML.xsl'),() )
};

xquery version "3.0";

module namespace app="http://localhost:8080/exist/apps/xq-institute/templates";

import module namespace templates="http://exist-db.org/xquery/templates" ;
import module namespace config="http://localhost:8080/exist/apps/xq-institute/config" at "config.xqm";
declare namespace util="http://exist-db.org/xquery/util";
declare namespace tei="http://www.tei-c.org/ns/1.0";

(:~
 : Browse using sort
 : Using user defined functions to modularize code
:)
declare %templates:wrap function app:browse-list-items($node as node(), $model as map(*)){
    for $play in collection($config:app-root || "/data")
    let $title := $play//tei:titleStmt/tei:title/text()
    (: NOTE: construct a more robust function to run through a list of stop words using tokenize?:)
    let $sort-title := replace(replace($title,'^The ',''),'^A ','')
    let $uri := base-uri($play)
    order by $sort-title
    return
        app:display-title($title,$uri)
};

declare function app:display-title($title as xs:string?,$uri as xs:anyURI?){

            {$title}

            HTML | PDF | XML

};

(:~
 : Retrieve play xml transform with xsl for html output
 : @param $uri passes internal uri for play
 : @param $view view used for output
 :
:)
declare %templates:wrap function app:view-play-html($node as node(), $model as map(*)){
    let $uri := request:get-parameter('uri', '')
    let $rec := xmldb:document($uri)
    return transform:transform($rec, doc('../resources/xsl/teiHTML.xsl'),() )
};


Fixed local documentation generation broken after the changes in r9054.

import module namespace doc2html = "http://www.zorba-xquery.com/modules/internal/xqdoc-lib";

declare variable $modulesPath     as xs:string external;
declare variable $xqdocBuildPath as xs:string external;
declare variable $indexHtmlPath  as xs:string external;

doc2html:main($modulesPath, $xqdocBuildPath, $indexHtmlPath)

import module namespace doc2html = "http://www.zorba-xquery.com/modules/xqdoc2html" at "xqdoc-lib.xq";

declare variable $modulesPath     as xs:string external;
declare variable $xqdocBuildPath as xs:string external;
declare variable $indexHtmlPath  as xs:string external;

doc2html:main($modulesPath, $xqdocBuildPath, $indexHtmlPath)


fixed one validation bug of editing admin user

xquery version "1.0";

(: ~
 : Module Name:             edit context webpage and XQuery
 :
 : Module Version           2.0
 :
 : Date                     31st July 2009
 :
 : Copyright                The cagrid consortium
 :
 : Module overview          edit context information
 :
 :)

(:~
 :    @author Rakesh Dhaval
      @author Puneet Mathur
 :    @version 0.2
 :
 :    User Management Page
~ :)

  import module namespace
  lib-forms="http://www.cagrid.org/xquery/library/forms"
  at "../edit/m-lib-forms.xquery";

  import module namespace
  lib-util="http://www.cagrid.org/xquery/library/util"
  at "../library/m-lib-util.xquery";

  import module namespace
  lib-rendering="http://www.cagrid.org/xquery/library/rendering"
  at "../web/m-lib-rendering.xquery";

  import module namespace
  lib-make-admin-item="http://www.cagrid.org/xquery/library/make-admin-item"
  at "../edit/m-lib-make-admin-item.xquery";

declare namespace openMDR = "http://www.cagrid.org/schema/openMDR";
declare namespace ISO11179= "http://www.cagrid.org/schema/ISO11179";
declare namespace session="http://exist-db.org/xquery/session";
declare namespace request="http://exist-db.org/xquery/request";
declare namespace response="http://exist-db.org/xquery/response";
declare namespace exist = "http://exist.sourceforge.net/NS/exist";
declare namespace util="http://exist-db.org/xquery/util";
declare namespace xmldb="http://exist-db.org/xquery/xmldb";

declare function local:success-page()
{
   let $calling-page := request:get-parameter("calling-page","")
   return

        if(local:validateUser()=true()) then
        (

This section will allow you to manage the different users wih their respective roles.
                A user can exist in one of thollowing three different roles :

1. dba

2. user

3. guest

                Action
                dba
                user
                guest

                New User
                Yes
                No
                No

                Edit User
                Yes
                No
                No

                Remove User
                Yes
                No
                No

Note: "Admin" is the superuser with dba role and has got all the privileges. Any other user with
         dba role cannot Edit or Remove Admin user.

         {local:process()}

        )
        else(

            Error : Access Denied !! Only users of "dba" group have access

            Return to maintenance menu

        )

};

declare function local:create-user() as element()*
{

    let $name := request:get-parameter("name", ()),
    $grp := request:get-parameter("groups", ()),
    $groups := if ($grp) then
        (
            if(contains($grp, ",")) then
            (
                tokenize($grp, "\s*,\s*")
            )
            else
            (
                $grp
            )
        )else(),
    $pass1 := request:get-parameter("pass1", ""),
    $pass2 := request:get-parameter("pass2", "")
    return

    if($name eq "") then
    (

	Error : UserName is missing !!!!

 {local:correct-user(-1, $name, $grp)}

    )
   (:
   else if($name != "") then
   (
                for $user in doc("/db/system/users.xml")//users/user
                    let $stored_username := xs:string($user/@name)
 	 return(
 	 	if($name eq $stored_username) then
 	 	(

			Error : UserName Already Exists !! Chooose a different Username!!!!

 {local:correct-user(-1, "", "")}

		)
		else()
	   )

   ) :)

    else if($grp eq "") then
    (

	Error : GroupName is missing !! Please specify atleast one group!!!!!

 {local:correct-user(-1, $name, $grp)}

    )

    else if($pass1 != $pass2 or $pass1 eq "") then
        (

	Error : Either Password is missing or Passwords are not identical !!!!

 {local:correct-user(-1, $name, $grp)}

        )
        else(

            xmldb:create-user($name, $pass1, $groups, ""),

            Success: User "{$name}" Created !!!

{local:display()}

          )
};

declare function local:display()
{

      <form>

                Name
                Groups

            {
                for $user in doc("/db/system/users.xml")//users/user
                    let $name := xs:string($user/@name),
                    $groups := string-join($user/group, ", ")
                order by $name return

                        <input type="radio" name="uid" value="{$user/@uid}"/>
                        {$name}
                        {$groups}

            }

                    <input type="submit" name="action" value="Edit"/>
                    <input type="submit" name="action" value="New User"/>
                    <input type="submit" name="action" value="Remove"/>

Return to maintenance menu
    </form>

} ;

declare function local:correct-user($uid as xs:integer, $name as xs:string, $groups as xs:string)  as element()
{

    <form action="{session:encode-url(request:get-uri())}" method="get">
        {local:edit-user($uid, $name, $groups)}
        <input type="hidden" name="panel" value="users"/>
    </form>

};

declare function local:edit-user($uid as xs:integer, $name as xs:string, $groups as xs:string) as element()
{

            User:
            {
                if($name eq "") then
                (
                    <input type="text" name="name"/>
                )
                else
                (
                    <input type="hidden" name="name" value="{$name}"/>{$name}
                )
            }

            Groups:
            <input type="text" name="groups" value="{$groups}"/>
            A comma-separated list of groups.
            Note: non-existing groups will be created automatically.

            Password:
            <input type="password" name="pass1"/>

            Repeat:
            <input type="password" name="pass2"/>

         {
            if($uid ge 0) then
            (
                <input type="checkbox" name="nopass"/> Leave password unchanged.
            )else()
        }

        {
            if($uid lt 0) then
            (

                <input type="submit" name="action" value="Create"/>
	            <input type="submit" name="action" value="Cancel"/>
            )
            else
            (

                <input type="submit" name="action" value="Change"/>
	 <input type="submit" name="action" value="Cancel"/>
            )

        }

        <input type="hidden" name="uid" value="{$uid}"/>

 };

declare function local:process()  as element()*
{
    let $action := request:get-parameter("action", "") ,
    $session_user  := session:get-attribute("username"),
    $current_user := xmldb:get-current-user()
    return
        if($action eq "Create") then
        (
            local:create-user()
        )
        else if($action eq "New User") then
        (
            local:correct-user(-1, "", "")
        )
       else if($action eq "Change") then
        (
            local:update-user()
        )
        else if($action eq "Edit") then
        (
            let $uid := request:get-parameter("uid", ()) return
            if(empty($uid) or xs:integer($uid) le 0)then
 	        (

Error : Select a User to Update !!!!

{local:display()}

	         )
      	     else
	         (
               		let $user := doc("/db/system/users.xml")//users/user[@uid = $uid] return
        			if( ($user/@name) eq "admin" and xmldb:get-current-user() != "admin" ) then
	      	        (

Error : You do not have permission to Edit the Admin User !!!!

{local:display()}

	       	        )
	       	        (:else if(($user/@name) eq xmldb:get-current-user() ) then
	       	        (

Error : You cannot Edit the Current Logged In User !!!!

{local:display()}

	       	        ) :)
       	            else(
       	             	     local:correct-user(xs:integer($uid), $user/@name, string-join($user/group, ", "))
		            )

              )

            )
        else if($action eq "Remove") then
        (
            local:remove-user()
        )
        else if($action eq "Cancel") then
        (

	       {local:display()}

        )
        else(

	       {local:display()}

        )

};

declare function local:validateUser() as xs:boolean
{
   let $hostname :=  request:get-hostname()

   let $database-uri := xs:string("xmldb:exist:///db")
   let $user := session:get-attribute("username")
   let $password := session:get-attribute("password")
   let $is-ssl :=  lib-util:checkSSL()
   return
           if(xmldb:is-admin-user($user)) then
           (
            	if (xmldb:login($database-uri, $user, $password))
              then (
		true()
	)
	else(
		false()
	)
          )
          else(
	          false()
          )

};

declare function local:update-user() as element()*
{

    let $name := request:get-parameter("name", ()),
    $grp := request:get-parameter("groups", ()),
    $groups := if ($grp) then
        (
            if(contains($grp, ",")) then
            (
                tokenize($grp, "\s*,\s*")
            )
            else
            (
                $grp
            )
        )else(),
    $pass1 := request:get-parameter("pass1", ""),
    $pass2 := request:get-parameter("pass2", ""),
    $nopass := request:get-parameter("nopass", ()),
    $pass := if($nopass) then () else $pass1,
    $uid := request:get-parameter("uid", ()) return

        if(not($nopass) and $pass1 ne $pass2)then
        (

        	Error : Passwords are not identical!!!!

 {local:correct-user(xs:integer($uid), $name, $grp)}

        )
        else if(not($nopass) and $pass eq "" )then
        (

        	Error : Please enter the Password or check the Leave Password Unchanged!!!!

 {local:correct-user(xs:integer($uid), $name, $grp)}

        )
        else if(empty($groups)) then
        (

        	Error : Please specify one group at least!!!!

 {local:correct-user(xs:integer($uid), $name, $grp)}

        )
        else
        (
            xmldb:change-user($name, $pass, $groups, ""),

            if(xmldb:get-current-user() eq $name) then
            (
                session:set-attribute("password", $pass)
            )else(),

            Success : User "{$name}" Updated !!!

{local:display()}

        )

};

declare function local:remove-user()
{
    if(empty(request:get-parameter("uid", ())) or xs:integer(request:get-parameter("uid", ())) le 0 )then
    (

            Error : Select a User to Remove !!!!

{local:display()}

    )
   else
   (
    let $uid := request:get-parameter("uid", ()),
    $name := doc("/db/system/users.xml")//user[@uid = $uid]/@name cast as xs:string return

        if($name eq xmldb:get-current-user() or $name eq "admin") then
        (

            Error : You cannot remove the Admin User or Current User!!!!

{local:display()}

        )
        (:
        else if (xmldb:is-admin-user($name) and xmldb:get-current-user() != "admin") then
        (

            Error : You do not have the permission to remove the user of "dba" group!!!!

{local:display()}

      ) :)
      else
      (

           { xmldb:delete-user($name) }
           Success : User "{$name}" Removed !!!

{local:display()}

        )
     )
};

declare option exist:serialize "media-type=text/html method=xhtml doctype-public=-//W3C//DTD XHTML 1.0 Transitional//EN doctype-system=http://www.w3.org/TR/2002/REC-xhtml1-20020801/DTD/xhtml1-transitional.dtd";

   session:create(),
   let $id := request:get-parameter('id','')
   let $title as xs:string := concat(" User Management", $id)

   return
      lib-rendering:txfrm-webpage(
      $title,
            local:success-page()
         )

xquery version "1.0";

(: ~
 : Module Name:             edit context webpage and XQuery
 :
 : Module Version           2.0
 :
 : Date                     31st July 2009
 :
 : Copyright                The cagrid consortium
 :
 : Module overview          edit context information
 :
 :)

(:~
 :    @author Rakesh Dhaval
      @author Puneet Mathur
 :    @version 0.2
 :
 :    User Management Page
~ :)

  import module namespace
  lib-forms="http://www.cagrid.org/xquery/library/forms"
  at "../edit/m-lib-forms.xquery";

  import module namespace
  lib-util="http://www.cagrid.org/xquery/library/util"
  at "../library/m-lib-util.xquery";

  import module namespace
  lib-rendering="http://www.cagrid.org/xquery/library/rendering"
  at "../web/m-lib-rendering.xquery";

  import module namespace
  lib-make-admin-item="http://www.cagrid.org/xquery/library/make-admin-item"
  at "../edit/m-lib-make-admin-item.xquery";

declare namespace openMDR = "http://www.cagrid.org/schema/openMDR";
declare namespace ISO11179= "http://www.cagrid.org/schema/ISO11179";
declare namespace session="http://exist-db.org/xquery/session";
declare namespace request="http://exist-db.org/xquery/request";
declare namespace response="http://exist-db.org/xquery/response";
declare namespace exist = "http://exist.sourceforge.net/NS/exist";
declare namespace util="http://exist-db.org/xquery/util";
declare namespace xmldb="http://exist-db.org/xquery/xmldb";

declare function local:success-page()
{
   let $calling-page := request:get-parameter("calling-page","")
   return

        if(local:validateUser()=true()) then
        (

This section will allow you to manage the different users wih their respective roles.
                A user can exist in one of thollowing three different roles :

1. dba

2. user

3. guest

                Action
                dba
                user
                guest

                New User
                Yes
                No
                No

                Edit User
                Yes
                No
                No

                Remove User
                Yes
                No
                No

Note: "Admin" is the superuser with dba role and has got all the privileges. Any other user with
         dba role cannot Edit or Remove Admin user.

         {local:process()}

        )
        else(

            Error : Access Denied !! Only users of "dba" group have access

            Return to maintenance menu

        )

};

declare function local:create-user() as element()*
{

    let $name := request:get-parameter("name", ()),
    $grp := request:get-parameter("groups", ()),
    $groups := if ($grp) then
        (
            if(contains($grp, ",")) then
            (
                tokenize($grp, "\s*,\s*")
            )
            else
            (
                $grp
            )
        )else(),
    $pass1 := request:get-parameter("pass1", ""),
    $pass2 := request:get-parameter("pass2", "")
    return

    if($name eq "") then
    (

	Error : UserName is missing !!!!

 {local:correct-user(-1, $name, $grp)}

    )

   else if($name != "") then
   (
                for $user in doc("/db/system/users.xml")//users/user
                    let $stored_username := xs:string($user/@name)
 	 return(
 	 	if($name eq $stored_username) then
 	 	(

			Error : UserName Already Exists !! Chooose a different Username!!!!

 {local:correct-user(-1, "", "")}

		)
		else()
	   )

   )

    else if($grp eq "") then
    (

	Error : GroupName is missing !! Please specify atleast one group!!!!!

 {local:correct-user(-1, $name, $grp)}

    )

    else if($pass1 != $pass2 or $pass1 eq "") then
        (

	Error : Either Password is missing or Passwords are not identical !!!!

 {local:correct-user(-1, $name, $grp)}

        )
        else(

            xmldb:create-user($name, $pass1, $groups, ""),

            Success: User "{$name}" Created !!!

{local:display()}

          )
};

declare function local:display()
{

      <form>

                Name
                Groups

            {
                for $user in doc("/db/system/users.xml")//users/user
                    let $name := xs:string($user/@name),
                    $groups := string-join($user/group, ", ")
                order by $name return

                        <input type="radio" name="uid" value="{$user/@uid}"/>
                        {$name}
                        {$groups}

            }

                    <input type="submit" name="action" value="Edit"/>
                    <input type="submit" name="action" value="New User"/>
                    <input type="submit" name="action" value="Remove"/>

Return to maintenance menu
    </form>

} ;

declare function local:correct-user($uid as xs:integer, $name as xs:string, $groups as xs:string)  as element()
{

    <form action="{session:encode-url(request:get-uri())}" method="get">
        {local:edit-user($uid, $name, $groups)}
        <input type="hidden" name="panel" value="users"/>
    </form>

};

declare function local:edit-user($uid as xs:integer, $name as xs:string, $groups as xs:string) as element()
{

            User:
            {
                if($name eq "") then
                (
                    <input type="text" name="name"/>
                )
                else
                (
                    <input type="hidden" name="name" value="{$name}"/>{$name}
                )
            }

            Groups:
            <input type="text" name="groups" value="{$groups}"/>
            A comma-separated list of groups.
            Note: non-existing groups will be created automatically.

            Password:
            <input type="password" name="pass1"/>

            Repeat:
            <input type="password" name="pass2"/>

         {
            if($uid ge 0) then
            (
                <input type="checkbox" name="nopass"/> Leave password unchanged.
            )else()
        }

        {
            if($uid lt 0) then
            (

                <input type="submit" name="action" value="Create"/>
	            <input type="submit" name="action" value="Cancel"/>
            )
            else
            (

                <input type="submit" name="action" value="Change"/>
	 <input type="submit" name="action" value="Cancel"/>
            )

        }

        <input type="hidden" name="uid" value="{$uid}"/>

 };

declare function local:process()  as element()*
{
    let $action := request:get-parameter("action", "") ,
    $session_user  := session:get-attribute("username"),
    $current_user := xmldb:get-current-user()
    return
        if($action eq "Create") then
        (
            local:create-user()
        )
        else if($action eq "New User") then
        (
            local:correct-user(-1, "", "")
        )
       else if($action eq "Change") then
        (
            local:update-user()
        )
        else if($action eq "Edit") then
        (
            let $uid := request:get-parameter("uid", ()) return
            if(empty($uid) or xs:integer($uid) le 0)then
 	        (

Error : Select a User to Update !!!!

{local:display()}

	         )
      	     else
	         (
               		let $user := doc("/db/system/users.xml")//users/user[@uid = $uid] return
        			if( ($user/@name) eq "admin" and xmldb:get-current-user() != "admin" ) then
	      	        (

Error : You do not have permission to Edit the Admin User !!!!

{local:display()}

	       	        )
	       	        else if(($user/@name) eq xmldb:get-current-user() ) then
	       	        (

Error : You cannot Edit the Current Logged In User !!!!

{local:display()}

	       	        )
       	            else(
       	             	     local:correct-user(xs:integer($uid), $user/@name, string-join($user/group, ", "))
		            )

              )

            )
        else if($action eq "Remove") then
        (
            local:remove-user()
        )
        else if($action eq "Cancel") then
        (

	       {local:display()}

        )
        else(

	       {local:display()}

        )

};

declare function local:validateUser() as xs:boolean
{
   let $hostname :=  request:get-hostname()

   let $database-uri := xs:string("xmldb:exist:///db")
   let $user := session:get-attribute("username")
   let $password := session:get-attribute("password")
   let $is-ssl :=  lib-util:checkSSL()
   return
           if(xmldb:is-admin-user($user)) then
           (
            	if (xmldb:login($database-uri, $user, $password))
              then (
		true()
	)
	else(
		false()
	)
          )
          else(
	          false()
          )

};

declare function local:update-user() as element()*
{

    let $name := request:get-parameter("name", ()),
    $grp := request:get-parameter("groups", ()),
    $groups := if ($grp) then
        (
            if(contains($grp, ",")) then
            (
                tokenize($grp, "\s*,\s*")
            )
            else
            (
                $grp
            )
        )else(),
    $pass1 := request:get-parameter("pass1", ""),
    $pass2 := request:get-parameter("pass2", ""),
    $nopass := request:get-parameter("nopass", ()),
    $pass := if($nopass) then () else $pass1,
    $uid := request:get-parameter("uid", ()) return

        if(not($nopass) and $pass1 ne $pass2)then
        (

        	Error : Passwords are not identical!!!!

 {local:correct-user(xs:integer($uid), $name, $grp)}

        )
        else if(not($nopass) and $pass eq "" )then
        (

        	Error : Please enter the Password or check the Leave Password Unchanged!!!!

 {local:correct-user(xs:integer($uid), $name, $grp)}

        )
        else if(empty($groups)) then
        (

        	Error : Please specify one group at least!!!!

 {local:correct-user(xs:integer($uid), $name, $grp)}

        )
        else
        (
            xmldb:change-user($name, $pass, $groups, ""),

            if(xmldb:get-current-user() eq $name) then
            (
                session:set-attribute("password", $pass)
            )else(),

            Success : User "{$name}" Updated !!!

{local:display()}

        )

};

declare function local:remove-user()
{
    if(empty(request:get-parameter("uid", ())) or xs:integer(request:get-parameter("uid", ())) le 0 )then
    (

            Error : Select a User to Remove !!!!

{local:display()}

    )
   else
   (
    let $uid := request:get-parameter("uid", ()),
    $name := doc("/db/system/users.xml")//user[@uid = $uid]/@name cast as xs:string return

        if($name eq xmldb:get-current-user() or $name eq "admin") then
        (

            Error : You cannot remove the Admin User or Current User!!!!

{local:display()}

        )
        (:
        else if (xmldb:is-admin-user($name) and xmldb:get-current-user() != "admin") then
        (

            Error : You do not have the permission to remove the user of "dba" group!!!!

{local:display()}

      ) :)
      else
      (

           { xmldb:delete-user($name) }
           Success : User "{$name}" Removed !!!

{local:display()}

        )
     )
};

declare option exist:serialize "media-type=text/html method=xhtml doctype-public=-//W3C//DTD XHTML 1.0 Transitional//EN doctype-system=http://www.w3.org/TR/2002/REC-xhtml1-20020801/DTD/xhtml1-transitional.dtd";

   session:create(),
   let $id := request:get-parameter('id','')
   let $title as xs:string := concat(" User Management", $id)

   return
      lib-rendering:txfrm-webpage(
      $title,
            local:success-page()
         )


DHFPROD-2856: Fix attributes issue with build error building search options in ML nightly build

(:
  Copyright 2012-2019 MarkLogic Corporation

  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 hent = "http://marklogic.com/data-hub/hub-entities";

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

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

declare variable $ENTITY-MODEL-COLLECTION := "http://marklogic.com/entity-services/models";

declare option xdmp:mapping "false";

declare function hent:get-model($entity-name as xs:string)
{
  hent:get-model($entity-name, ())
};

declare function hent:get-model($entity-name as xs:string, $used-models as xs:string*)
{
  let $model :=
    let $_ := fn:collection($ENTITY-MODEL-COLLECTION)[lower-case(info/title) = lower-case($entity-name)]
    return
      if (fn:count($_) > 1) then
        fn:head(fn:collection($ENTITY-MODEL-COLLECTION)[info/title = $entity-name])
      else
        $_
  where fn:exists($model)
  return
    let $model-map as map:map? := $model
    let $refs := $model//*[fn:local-name(.) = '$ref'][fn:starts-with(., "#/definitions")] ! fn:replace(., "#/definitions/", "")
    let $definitions := map:get($model-map, "definitions")
    let $_ :=
      for $ref in $refs[fn:not(. = $used-models)]
      let $m :=
        if (fn:empty(map:get($definitions, $ref))) then
          let $other-model as map:map? := hent:get-model($ref, ($used-models, $entity-name))
          let $other-defs := map:get($other-model, "definitions")
          for $key in map:keys($other-defs)
          return
            map:put($definitions, $key, map:get($other-defs, $key))
        else ()
      return ()
    return $model-map
};

declare function hent:uber-model() as map:map
{
  hent:uber-model(fn:collection($ENTITY-MODEL-COLLECTION)/object-node())
};

declare function hent:uber-model($models as object-node()*) as map:map
{
  let $uber-model := map:map()
  let $definitions :=
    let $m := map:map()
    let $_ :=
      for $model as map:map in $models
      let $defs := map:get($model, "definitions")
      for $key in map:keys($defs)
      return
        map:put($m, $key, map:get($defs, $key))
    return
      map:put($uber-model, "definitions", $m)
  return
    $uber-model
};

declare function hent:wrap-duplicates(
  $duplicate-map as map:map,
  $property-name as xs:string,
  $item as element()
) as item()
{
  if (map:contains($duplicate-map, $property-name))
  then
    comment { "This item is a duplicate and is commented out so as to create a valid artifact.
",
    xdmp:quote($item),
    "
"
    }
  else (
    map:put($duplicate-map, $property-name, true()),
    $item)
};

(:
  this method doctors the output from ES
  because of https://github.com/marklogic/entity-services/issues/359
:)
declare %private function hent:fix-options($nodes as node()*)
{
  for $n in $nodes
  return
    typeswitch($n)
      case element(search:options) return
        element { fn:node-name($n) } {
          $n/namespace::node(),
          $n/@*,
          <search:constraint name="Collection">
            <search:collection/>
          </search:constraint>,
          <search:constraint name="createdByJob">
            <search:value>
              <search:field name="datahubCreatedByJob"/>
            </search:value>
          </search:constraint>,
          <search:constraint name="createdByStep">
            <search:value>
              <search:field name="datahubCreatedByStep"/>
            </search:value>
          </search:constraint>,
          hent:fix-options($n/node())
        }
      case element(search:additional-query) return ()
      case element(search:return-facets) return <search:return-facets>true</search:return-facets>
      case element() return
        element { fn:node-name($n) } {
          $n/namespace::node(),
          $n/@*,
          hent:fix-options($n/node()),

          let $is-range-constraint := $n[self::search:range] and $n/..[self::search:constraint]
          where $is-range-constraint and fn:not($n/search:facet-option[starts-with(., "limit=")])
          return <search:facet-option>limit=25</search:facet-option>
        }
      case text() return
        fn:replace($n, "es:", "*:")
      default return $n
};

declare function hent:dump-search-options($entities as json:array)
{
  let $uber-model := hent:uber-model(json:array-values($entities) ! xdmp:to-json(.)/object-node())
  return
  (: call fix-options because of https://github.com/marklogic/entity-services/issues/359 :)
    hent:fix-options(es:search-options-generate($uber-model))
};

declare function hent:dump-pii($entities as json:array)
{
  let $uber-model := hent:uber-model(json:array-values($entities) ! xdmp:to-json(.)/object-node())
  return es:pii-generate($uber-model)
};

declare function hent:dump-indexes($entities as json:array)
{
  let $uber-model := hent:uber-model(json:array-values($entities) ! xdmp:to-json(.)/object-node())

  let $database-config := xdmp:from-json(es:database-properties-generate($uber-model))

  let $_ :=
    for $x in ("database-name", "schema-database", "triple-index", "collection-lexicon")
    return
      map:delete($database-config, $x)

  let $_ :=
    for $idx in map:get($database-config, "range-path-index") ! json:array-values(.)
    return
      map:put($idx, "path-expression", fn:replace(map:get($idx, "path-expression"), "es:", "*:"))

  let $_ := remove-duplicate-range-indexes($database-config)

  return
    xdmp:to-json($database-config)
};

(:
es:database-properties-generate will generate duplicate range indexes when e.g. two entities have properties with the
same name and namespace and are both configured to have range indexes. This function removes duplicates, where
duplicates are considered to have the same local name, namespace URI, and collation.
:)
declare function hent:remove-duplicate-range-indexes($database-config as item())
{
  let $indexes := map:get($database-config, "range-element-index")
  return
    if (fn:exists($indexes)) then
      let $index-map := map:map()
      let $_ :=
        for $index in json:array-values($indexes)
        let $key := fn:string-join(
          (
            "localname", map:get($index, "localname"),
            "namespace", map:get($index, "namespace-uri"),
            "collation", map:get($index, "collation")
          ), "-"
        )
        where fn:not(map:contains($index-map, $key))
        return map:put($index-map, $key, $index)

      let $deduplicated-indexes := json:array()
      let $_ := map:keys($index-map) ! json:array-push($deduplicated-indexes, map:get($index-map, .))
      let $_ := map:put($database-config, "range-element-index", $deduplicated-indexes)
      return ()
    else
      let $_ := map:put($database-config, "range-element-index", json:array())
      return ()
};

declare variable $generated-primary-key-column as xs:string := "DataHubGeneratedPrimaryKey";
declare variable $generated-primary-key-expression as xs:string := "xdmp:node-uri(.) || '#' || fn:position()";

declare function hent:dump-tde($entities as json:array)
{
  let $entity-values as map:map* := json:array-values($entities)
  let $uber-model := hent:uber-model($entity-values ! xdmp:to-json(.)/object-node())
  let $_set-info := $uber-model => map:put("info", fn:head($entity-values) => map:get("info"))
  let $uber-definitions := $uber-model => map:get("definitions")
  (: Primary keys are required for each definition in an entity. If the primary key is missing, we'll help out by using the doc URI and position as the primary key. :)
  let $_set-primary-keys-for-TDE :=
    for $definition-type in map:keys($uber-definitions)
    let $definition := $uber-definitions => map:get($definition-type)
    where fn:empty($definition => map:get("primaryKey"))
    return (
      $definition => map:put("primaryKey", $generated-primary-key-column),
      $definition => map:get("properties") => map:put($generated-primary-key-column, map:entry("datatype", "string"))
    )
  let $entity-model-contexts := map:keys($uber-definitions) ! ("./" || .)
  return hent:fix-tde(es:extraction-template-generate($uber-model), $entity-model-contexts, $uber-definitions)
};

declare variable $default-nullable as element(tde:nullable) := element tde:nullable {fn:true()};
declare variable $default-invalid-values as element(tde:invalid-values) := element tde:invalid-values {"ignore"};
(:
  this method doctors the TDE output from ES
:)
declare function hent:fix-tde($nodes as node()*, $entity-model-contexts as xs:string*, $uber-definitions as map:map)
{
  for $n in $nodes
  return
    typeswitch($n)
      case document-node() return
        document {
          hent:fix-tde($n/node(), $entity-model-contexts, $uber-definitions)
        }
      case element(tde:nullable) return
        $default-nullable
      case element(tde:invalid-values) return
        $default-invalid-values
      case element(tde:val) return
        element { fn:node-name($n) } {
          $n/namespace::node(),
          let $col-name := fn:string($n/../tde:name)
          return
            if (fn:ends-with($col-name, $generated-primary-key-column)) then
              $generated-primary-key-expression
            else if (fn:starts-with($n, $col-name)) then
              let $parts := fn:tokenize($n, "/")
              let $entity-definition := $uber-definitions => map:get(fn:string($parts[2]))
              return
                if (fn:exists($entity-definition)) then
                  let $primary-key := $entity-definition => map:get("primaryKey")
                  return
                    if ($primary-key = $generated-primary-key-column) then
                      $generated-primary-key-expression
                    else
                      fn:string($n) || "/" || $primary-key
                else
                  hent:fix-tde($n/node(), $entity-model-contexts, $uber-definitions)
            else
              hent:fix-tde($n/node(), $entity-model-contexts, $uber-definitions)
        }
      case element(tde:context) return
        element { fn:node-name($n) } {
          $n/namespace::node(),
          if ($n = $entity-model-contexts) then
            fn:replace(fn:string($n),"^\./", ".//")
          else
            $n/node()
        }
      case element(tde:column) return
        element { fn:node-name($n) } {
          $n/namespace::node(),
          $n/@*,
          hent:fix-tde($n/* except $n/(tde:nullable|tde:invalid-values), $entity-model-contexts, $uber-definitions),
          $default-nullable,
          $default-invalid-values
        }
      case element(tde:subject)|element(tde:predicate)|element(tde:object) return
        element { fn:node-name($n) } {
          $n/namespace::node(),
          hent:fix-tde($n/* except $n/tde:invalid-values, $entity-model-contexts, $uber-definitions),
          $default-invalid-values
        }
      case element(tde:template) return
        element { fn:node-name($n) } {
          $n/namespace::node(),
          $n/@*,
          let $context-item :=  fn:replace(fn:string($n/tde:context), "\./", "")
          let $parent-context-item := fn:replace(fn:string($n/../../tde:context), "\./", "")
          let $is-join-template := $n/tde:rows/tde:row/tde:view-name = $parent-context-item  || "_" || $context-item
          let $rows := $n/tde:rows/tde:row
          return
            if ($is-join-template) then (
              hent:fix-tde($n/tde:context, $entity-model-contexts, $uber-definitions),
              element tde:rows {
                element tde:row {
                  $rows/(tde:schema-name|tde:view-name|tde:view-layout),
                  element tde:columns {
                    let $join-prefix := $context-item || "_"
                    for $column in $rows/tde:columns/tde:column
                    return
                      element tde:column {
                        $column/@*,
                        if (fn:starts-with($column/tde:name, $join-prefix)) then (
                          hent:fix-tde($column/(tde:name|tde:scalar-type), $entity-model-contexts, $uber-definitions),
                          let $tde-val := fn:string($column/tde:val)
                          let $primary-key := $uber-definitions => map:get($tde-val) => map:get("primaryKey")
                          return
                            element tde:val {
                              if ($primary-key = $generated-primary-key-column) then
                                $generated-primary-key-expression
                              else
                                $tde-val || "/" || $primary-key
                            },
                          $default-nullable,
                          $default-invalid-values,
                          hent:fix-tde($column/(tde:default|tde:reindexing|tde:collation), $entity-model-contexts, $uber-definitions)
                        ) else
                          hent:fix-tde($column/node(), $entity-model-contexts, $uber-definitions)
                      }
                  }
                }
              }
            ) else
              hent:fix-tde($n/node(), $entity-model-contexts, $uber-definitions)
        }
      case element() return
        element { fn:node-name($n) } {
          $n/namespace::node(),
          hent:fix-tde(($n/@*, $n/node()), $entity-model-contexts, $uber-definitions)
        }
      case text() return
        fn:replace(
          fn:replace($n, "^\.\./(.+)$", "(../$1|parent::array-node()/../$1)"),
          "\./" || $generated-primary-key-column,
          $generated-primary-key-expression
        )
      default return $n
};

declare variable $number-types as xs:string+ := ("byte","decimal","double","float","int","integer","long","negativeInteger","nonNegativeInteger","nonPositiveInteger","positiveInteger","short","unsignedLong","unsignedInt","unsignedShort","unsignedByte");
declare variable $string-types as xs:string+ := "dateTime";

declare function hent:json-schema-generate($entity-title as xs:string, $uber-model as map:map)
{
  let $uber-model := map:new((
  (: Ensure we're not change a map for anyone else :)
  map:map(document{$uber-model}/*),
  map:entry("language", "zxx"),
  map:entry("$schema", "http://json-schema.org/draft-07/schema#")
  ))
  let $definitions := $uber-model => map:get("definitions")
  (: JSON Schema needs an extra level of wrapping to account for Entity Model label wrapping it. :)
  let $_nest-refs :=
    for $definition-type in map:keys($definitions)
    let $definition-properties := $definitions => map:get($definition-type) => map:get("properties")
    for $property-name in map:keys($definition-properties)
    let $property := $definition-properties => map:get($property-name)
    let $property-items := $property => map:get("items")
    let $datatype := $property => map:get("datatype")
    let $_set-types := (
      $property => map:put("type", if ($datatype = $number-types) then "number" else if ($datatype = $string-types) then "string" else $datatype),
      $property => map:delete("datatype"),
      if ($property-items instance of map:map) then (
        let $items-datatype := $property => map:get("datatype")
        return (
          $property-items => map:put("type", if ($items-datatype = $number-types) then "number" else if ($items-datatype = $string-types) then "string" else $datatype),
          $property-items => map:delete("datatype"))
      ) else ()
    )
    return
    (: references can be in the property or in items for arrays :)
      if ($property => map:contains("$ref")) then
        map:put($definition-properties, $property-name,
          map:new((
            map:entry("type", "object"),
            map:entry("properties",
              map:entry(fn:tokenize(map:get($property,"$ref"),"/")[fn:last()], $property)
            )
          ))
        )
      else if ($property-items instance of map:map and $property-items => map:contains("$ref")) then
        map:put($property, "items",
          map:new((
            map:entry("type", "object"),
            map:entry("properties",
              map:entry(fn:tokenize(map:get($property-items,"$ref"),"/")[fn:last()], $property-items)
            )
          ))
        )
      else ()
  let $_set-info := (
    $uber-model => map:put("properties", map:entry($entity-title, map:entry("$ref", "#/definitions/"||$entity-title)))
  )
  return xdmp:to-json($uber-model)
};

(:
  Copyright 2012-2019 MarkLogic Corporation

  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 hent = "http://marklogic.com/data-hub/hub-entities";

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

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

declare variable $ENTITY-MODEL-COLLECTION := "http://marklogic.com/entity-services/models";

declare option xdmp:mapping "false";

declare function hent:get-model($entity-name as xs:string)
{
  hent:get-model($entity-name, ())
};

declare function hent:get-model($entity-name as xs:string, $used-models as xs:string*)
{
  let $model :=
    let $_ := fn:collection($ENTITY-MODEL-COLLECTION)[lower-case(info/title) = lower-case($entity-name)]
    return
      if (fn:count($_) > 1) then
        fn:head(fn:collection($ENTITY-MODEL-COLLECTION)[info/title = $entity-name])
      else
        $_
  where fn:exists($model)
  return
    let $model-map as map:map? := $model
    let $refs := $model//*[fn:local-name(.) = '$ref'][fn:starts-with(., "#/definitions")] ! fn:replace(., "#/definitions/", "")
    let $definitions := map:get($model-map, "definitions")
    let $_ :=
      for $ref in $refs[fn:not(. = $used-models)]
      let $m :=
        if (fn:empty(map:get($definitions, $ref))) then
          let $other-model as map:map? := hent:get-model($ref, ($used-models, $entity-name))
          let $other-defs := map:get($other-model, "definitions")
          for $key in map:keys($other-defs)
          return
            map:put($definitions, $key, map:get($other-defs, $key))
        else ()
      return ()
    return $model-map
};

declare function hent:uber-model() as map:map
{
  hent:uber-model(fn:collection($ENTITY-MODEL-COLLECTION)/object-node())
};

declare function hent:uber-model($models as object-node()*) as map:map
{
  let $uber-model := map:map()
  let $definitions :=
    let $m := map:map()
    let $_ :=
      for $model as map:map in $models
      let $defs := map:get($model, "definitions")
      for $key in map:keys($defs)
      return
        map:put($m, $key, map:get($defs, $key))
    return
      map:put($uber-model, "definitions", $m)
  return
    $uber-model
};

declare function hent:wrap-duplicates(
  $duplicate-map as map:map,
  $property-name as xs:string,
  $item as element()
) as item()
{
  if (map:contains($duplicate-map, $property-name))
  then
    comment { "This item is a duplicate and is commented out so as to create a valid artifact.
",
    xdmp:quote($item),
    "
"
    }
  else (
    map:put($duplicate-map, $property-name, true()),
    $item)
};

(:
  this method doctors the output from ES
  because of https://github.com/marklogic/entity-services/issues/359
:)
declare %private function hent:fix-options($nodes as node()*)
{
  for $n in $nodes
  return
    typeswitch($n)
      case element(search:options) return
        element { fn:node-name($n) } {
          $n/namespace::node(),
          <search:constraint name="Collection">
            <search:collection/>
          </search:constraint>,
          <search:constraint name="createdByJob">
            <search:value>
              <search:field name="datahubCreatedByJob"/>
            </search:value>
          </search:constraint>,
          <search:constraint name="createdByStep">
            <search:value>
              <search:field name="datahubCreatedByStep"/>
            </search:value>
          </search:constraint>,
          hent:fix-options(($n/@*, $n/node()))
        }
      case element(search:additional-query) return ()
      case element(search:return-facets) return <search:return-facets>true</search:return-facets>
      case element() return
        element { fn:node-name($n) } {
          $n/namespace::node(),
          hent:fix-options(($n/@*, $n/node())),

          let $is-range-constraint := $n[self::search:range] and $n/..[self::search:constraint]
          where $is-range-constraint and fn:not($n/search:facet-option[starts-with(., "limit=")])
          return <search:facet-option>limit=25</search:facet-option>
        }
      case text() return
        fn:replace($n, "es:", "*:")
      default return $n
};

declare function hent:dump-search-options($entities as json:array)
{
  let $uber-model := hent:uber-model(json:array-values($entities) ! xdmp:to-json(.)/object-node())
  return
  (: call fix-options because of https://github.com/marklogic/entity-services/issues/359 :)
    hent:fix-options(es:search-options-generate($uber-model))
};

declare function hent:dump-pii($entities as json:array)
{
  let $uber-model := hent:uber-model(json:array-values($entities) ! xdmp:to-json(.)/object-node())
  return es:pii-generate($uber-model)
};

declare function hent:dump-indexes($entities as json:array)
{
  let $uber-model := hent:uber-model(json:array-values($entities) ! xdmp:to-json(.)/object-node())

  let $database-config := xdmp:from-json(es:database-properties-generate($uber-model))

  let $_ :=
    for $x in ("database-name", "schema-database", "triple-index", "collection-lexicon")
    return
      map:delete($database-config, $x)

  let $_ :=
    for $idx in map:get($database-config, "range-path-index") ! json:array-values(.)
    return
      map:put($idx, "path-expression", fn:replace(map:get($idx, "path-expression"), "es:", "*:"))

  let $_ := remove-duplicate-range-indexes($database-config)

  return
    xdmp:to-json($database-config)
};

(:
es:database-properties-generate will generate duplicate range indexes when e.g. two entities have properties with the
same name and namespace and are both configured to have range indexes. This function removes duplicates, where
duplicates are considered to have the same local name, namespace URI, and collation.
:)
declare function hent:remove-duplicate-range-indexes($database-config as item())
{
  let $indexes := map:get($database-config, "range-element-index")
  return
    if (fn:exists($indexes)) then
      let $index-map := map:map()
      let $_ :=
        for $index in json:array-values($indexes)
        let $key := fn:string-join(
          (
            "localname", map:get($index, "localname"),
            "namespace", map:get($index, "namespace-uri"),
            "collation", map:get($index, "collation")
          ), "-"
        )
        where fn:not(map:contains($index-map, $key))
        return map:put($index-map, $key, $index)

      let $deduplicated-indexes := json:array()
      let $_ := map:keys($index-map) ! json:array-push($deduplicated-indexes, map:get($index-map, .))
      let $_ := map:put($database-config, "range-element-index", $deduplicated-indexes)
      return ()
    else
      let $_ := map:put($database-config, "range-element-index", json:array())
      return ()
};

declare variable $generated-primary-key-column as xs:string := "DataHubGeneratedPrimaryKey";
declare variable $generated-primary-key-expression as xs:string := "xdmp:node-uri(.) || '#' || fn:position()";

declare function hent:dump-tde($entities as json:array)
{
  let $entity-values as map:map* := json:array-values($entities)
  let $uber-model := hent:uber-model($entity-values ! xdmp:to-json(.)/object-node())
  let $_set-info := $uber-model => map:put("info", fn:head($entity-values) => map:get("info"))
  let $uber-definitions := $uber-model => map:get("definitions")
  (: Primary keys are required for each definition in an entity. If the primary key is missing, we'll help out by using the doc URI and position as the primary key. :)
  let $_set-primary-keys-for-TDE :=
    for $definition-type in map:keys($uber-definitions)
    let $definition := $uber-definitions => map:get($definition-type)
    where fn:empty($definition => map:get("primaryKey"))
    return (
      $definition => map:put("primaryKey", $generated-primary-key-column),
      $definition => map:get("properties") => map:put($generated-primary-key-column, map:entry("datatype", "string"))
    )
  let $entity-model-contexts := map:keys($uber-definitions) ! ("./" || .)
  return hent:fix-tde(es:extraction-template-generate($uber-model), $entity-model-contexts, $uber-definitions)
};

declare variable $default-nullable as element(tde:nullable) := element tde:nullable {fn:true()};
declare variable $default-invalid-values as element(tde:invalid-values) := element tde:invalid-values {"ignore"};
(:
  this method doctors the TDE output from ES
:)
declare function hent:fix-tde($nodes as node()*, $entity-model-contexts as xs:string*, $uber-definitions as map:map)
{
  for $n in $nodes
  return
    typeswitch($n)
      case document-node() return
        document {
          hent:fix-tde($n/node(), $entity-model-contexts, $uber-definitions)
        }
      case element(tde:nullable) return
        $default-nullable
      case element(tde:invalid-values) return
        $default-invalid-values
      case element(tde:val) return
        element { fn:node-name($n) } {
          $n/namespace::node(),
          let $col-name := fn:string($n/../tde:name)
          return
            if (fn:ends-with($col-name, $generated-primary-key-column)) then
              $generated-primary-key-expression
            else if (fn:starts-with($n, $col-name)) then
              let $parts := fn:tokenize($n, "/")
              let $entity-definition := $uber-definitions => map:get(fn:string($parts[2]))
              return
                if (fn:exists($entity-definition)) then
                  let $primary-key := $entity-definition => map:get("primaryKey")
                  return
                    if ($primary-key = $generated-primary-key-column) then
                      $generated-primary-key-expression
                    else
                      fn:string($n) || "/" || $primary-key
                else
                  hent:fix-tde($n/node(), $entity-model-contexts, $uber-definitions)
            else
              hent:fix-tde($n/node(), $entity-model-contexts, $uber-definitions)
        }
      case element(tde:context) return
        element { fn:node-name($n) } {
          $n/namespace::node(),
          if ($n = $entity-model-contexts) then
            fn:replace(fn:string($n),"^\./", ".//")
          else
            $n/node()
        }
      case element(tde:column) return
        element { fn:node-name($n) } {
          $n/namespace::node(),
          $n/@*,
          hent:fix-tde($n/* except $n/(tde:nullable|tde:invalid-values), $entity-model-contexts, $uber-definitions),
          $default-nullable,
          $default-invalid-values
        }
      case element(tde:subject)|element(tde:predicate)|element(tde:object) return
        element { fn:node-name($n) } {
          $n/namespace::node(),
          hent:fix-tde($n/* except $n/tde:invalid-values, $entity-model-contexts, $uber-definitions),
          $default-invalid-values
        }
      case element(tde:template) return
        element { fn:node-name($n) } {
          $n/namespace::node(),
          $n/@*,
          let $context-item :=  fn:replace(fn:string($n/tde:context), "\./", "")
          let $parent-context-item := fn:replace(fn:string($n/../../tde:context), "\./", "")
          let $is-join-template := $n/tde:rows/tde:row/tde:view-name = $parent-context-item  || "_" || $context-item
          let $rows := $n/tde:rows/tde:row
          return
            if ($is-join-template) then (
              hent:fix-tde($n/tde:context, $entity-model-contexts, $uber-definitions),
              element tde:rows {
                element tde:row {
                  $rows/(tde:schema-name|tde:view-name|tde:view-layout),
                  element tde:columns {
                    let $join-prefix := $context-item || "_"
                    for $column in $rows/tde:columns/tde:column
                    return
                      element tde:column {
                        $column/@*,
                        if (fn:starts-with($column/tde:name, $join-prefix)) then (
                          hent:fix-tde($column/(tde:name|tde:scalar-type), $entity-model-contexts, $uber-definitions),
                          let $tde-val := fn:string($column/tde:val)
                          let $primary-key := $uber-definitions => map:get($tde-val) => map:get("primaryKey")
                          return
                            element tde:val {
                              if ($primary-key = $generated-primary-key-column) then
                                $generated-primary-key-expression
                              else
                                $tde-val || "/" || $primary-key
                            },
                          $default-nullable,
                          $default-invalid-values,
                          hent:fix-tde($column/(tde:default|tde:reindexing|tde:collation), $entity-model-contexts, $uber-definitions)
                        ) else
                          hent:fix-tde($column/node(), $entity-model-contexts, $uber-definitions)
                      }
                  }
                }
              }
            ) else
              hent:fix-tde($n/node(), $entity-model-contexts, $uber-definitions)
        }
      case element() return
        element { fn:node-name($n) } {
          $n/namespace::node(),
          hent:fix-tde(($n/@*, $n/node()), $entity-model-contexts, $uber-definitions)
        }
      case text() return
        fn:replace(
          fn:replace($n, "^\.\./(.+)$", "(../$1|parent::array-node()/../$1)"),
          "\./" || $generated-primary-key-column,
          $generated-primary-key-expression
        )
      default return $n
};

declare variable $number-types as xs:string+ := ("byte","decimal","double","float","int","integer","long","negativeInteger","nonNegativeInteger","nonPositiveInteger","positiveInteger","short","unsignedLong","unsignedInt","unsignedShort","unsignedByte");
declare variable $string-types as xs:string+ := "dateTime";

declare function hent:json-schema-generate($entity-title as xs:string, $uber-model as map:map)
{
  let $uber-model := map:new((
  (: Ensure we're not change a map for anyone else :)
  map:map(document{$uber-model}/*),
  map:entry("language", "zxx"),
  map:entry("$schema", "http://json-schema.org/draft-07/schema#")
  ))
  let $definitions := $uber-model => map:get("definitions")
  (: JSON Schema needs an extra level of wrapping to account for Entity Model label wrapping it. :)
  let $_nest-refs :=
    for $definition-type in map:keys($definitions)
    let $definition-properties := $definitions => map:get($definition-type) => map:get("properties")
    for $property-name in map:keys($definition-properties)
    let $property := $definition-properties => map:get($property-name)
    let $property-items := $property => map:get("items")
    let $datatype := $property => map:get("datatype")
    let $_set-types := (
      $property => map:put("type", if ($datatype = $number-types) then "number" else if ($datatype = $string-types) then "string" else $datatype),
      $property => map:delete("datatype"),
      if ($property-items instance of map:map) then (
        let $items-datatype := $property => map:get("datatype")
        return (
          $property-items => map:put("type", if ($items-datatype = $number-types) then "number" else if ($items-datatype = $string-types) then "string" else $datatype),
          $property-items => map:delete("datatype"))
      ) else ()
    )
    return
    (: references can be in the property or in items for arrays :)
      if ($property => map:contains("$ref")) then
        map:put($definition-properties, $property-name,
          map:new((
            map:entry("type", "object"),
            map:entry("properties",
              map:entry(fn:tokenize(map:get($property,"$ref"),"/")[fn:last()], $property)
            )
          ))
        )
      else if ($property-items instance of map:map and $property-items => map:contains("$ref")) then
        map:put($property, "items",
          map:new((
            map:entry("type", "object"),
            map:entry("properties",
              map:entry(fn:tokenize(map:get($property-items,"$ref"),"/")[fn:last()], $property-items)
            )
          ))
        )
      else ()
  let $_set-info := (
    $uber-model => map:put("properties", map:entry($entity-title, map:entry("$ref", "#/definitions/"||$entity-title)))
  )
  return xdmp:to-json($uber-model)
};


Attempt to revert to trunk.

Attempt to revert to trunk.

(:
 : Copyright 2006-2009 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.
:)

import module namespace util = "http://www.zorba-xquery.com/diagnostic/util" at "diagnostic_util.xq";

declare function local:make-zed-defines( $doc ) as xs:string*
{
  for $entry in ( $doc//entry )
  let $key := $entry/@key
  return
    if ( contains( $key, ' ' ) )
    then ()
    else
      let $full_key :=
        if ( $entry/parent::diagnostic )
        then concat( $entry/parent::diagnostic/@code, "_", $key )
        else $key
      return concat( "#define ZED_", $full_key, ' "~', $full_key, '"' )
};

declare variable $input external;

string-join(
  ( util:copyright(),
    '#ifndef ZORBA_DIAGNOSTICS_ZED_KEYS',
    '#define ZORBA_DIAGNOSTICS_ZED_KEYS',
    '',
    local:make-zed-defines( $input ),
    '',
    '#endif /* ZORBA_DIAGNOSTICS_ZED_KEYS */',
    '/*',
    ' * Local variables:',
    ' * mode: c++',
    ' * End:',
    ' */',
    '/* vim:set et sw=2 ts=2: */'
  ),
  $util:newline
),
$util:newline

(: vim:set syntax=xquery et sw=2 ts=2: :)