diff --git a/src/vue-poc/components/core.js b/src/vue-poc/components/core.js
index 2eb0d2c..0d69a52 100644
--- a/src/vue-poc/components/core.js
+++ b/src/vue-poc/components/core.js
@@ -54,6 +54,7 @@ const router = new VueRouter({
{ path: '/eval', component: Eval,meta:{title:"Evaluate XQuery"} },
{ path: '/logs', component: Log,meta:{title:"Server logs"} },
{ path: '/tasks', component: Task,meta:{title:"Runnable tasks"} },
+ { path: '/tasks/model', component: Model,meta:{title:"build model"} },
{ path: '/jobs', component: Job,meta:{title:"Jobs"} },
{ path: '*', component: Notfound,meta:{title:"Page not found"} }
],
@@ -94,42 +95,42 @@ const app = new Vue({
text: 'Collections' ,
model: false,
children: [
- {href: 'database', text: 'Databases',icon: 'account_balance' },
- {href: 'files', text: 'File system',icon: 'folder' },
- {href: 'edit',text: 'edit',icon: 'mode_edit'},
- {href: 'history',text: 'history',icon: 'history'},
- {href: 'logs',text: 'Server logs',icon: 'dns'}
+ {href: '/database', text: 'Databases',icon: 'account_balance' },
+ {href: '/files', text: 'File system',icon: 'folder' },
+ {href: '/edit',text: 'edit',icon: 'mode_edit'},
+ {href: '/history',text: 'history',icon: 'history'},
+ {href: '/logs',text: 'Server logs',icon: 'dns'}
]},
{
icon: 'directions_run',
text: 'Actions' ,
model: false,
children: [
- {href: 'eval',text: 'Query',icon: 'play_circle_outline'},
- {href: 'jobs',text: 'Running jobs',icon: 'dashboard'},
- {href: 'tasks',text: 'Tasks',icon: 'history'},
+ {href: '/eval',text: 'Query',icon: 'play_circle_outline'},
+ {href: '/jobs',text: 'Running jobs',icon: 'dashboard'},
+ {href: '/tasks',text: 'Tasks',icon: 'history'}
]},
{
icon: 'more_horiz',
text: 'More' ,
model: false,
children: [
- {href: 'people',text: 'People',icon: 'person'},
- {href: 'select',text: 'select',icon: 'extension'},
- {href: 'puzzle',text: 'Puzzle',icon: 'extension'},
- {href: 'images',text: 'Images',icon: 'camera_roll'},
- {href: 'tabs',text: 'tabs',icon: 'switch_camera'},
- {href: 'ping',text: 'ping',icon: 'update'},
- {href: 'thumbnail',text: 'thumbnail',icon: 'touch_app'}
+ {href: '/people',text: 'People',icon: 'person'},
+ {href: '/select',text: 'select',icon: 'extension'},
+ {href: '/puzzle',text: 'Puzzle',icon: 'extension'},
+ {href: '/images',text: 'Images',icon: 'camera_roll'},
+ {href: '/tabs',text: 'tabs',icon: 'switch_camera'},
+ {href: '/ping',text: 'ping',icon: 'update'},
+ {href: '/thumbnail',text: 'thumbnail',icon: 'touch_app'}
]},
- {href: 'settings',text: 'settings',icon: 'settings' }
+ {href: '/settings',text: 'settings',icon: 'settings' }
]
}},
methods: {
search(){
- this.$router.push({path: 'search',query: { q: this.q }})
+ this.$router.push({path: '/search',query: { q: this.q }})
},
logout(){
HTTP.get("logout").then(r=>{
diff --git a/src/vue-poc/components/nav-list.vue b/src/vue-poc/components/nav-list.vue
index edb16fd..a049fd9 100644
--- a/src/vue-poc/components/nav-list.vue
+++ b/src/vue-poc/components/nav-list.vue
@@ -30,9 +30,7 @@
{{ item.model ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}
-
-
-
+
diff --git a/src/vue-poc/expath-pkg.xml b/src/vue-poc/expath-pkg.xml
index 78e4fde..e35b7fb 100644
--- a/src/vue-poc/expath-pkg.xml
+++ b/src/vue-poc/expath-pkg.xml
@@ -2,8 +2,8 @@
abbrev="vue-poc" version="0.0.3" spec="1.0">
vue-poc test of vue.js.
-
-
+
+
diff --git a/src/vue-poc/features/collection/collections.xqm b/src/vue-poc/features/collection/collections.xqm
index a3df57f..de248a6 100644
--- a/src/vue-poc/features/collection/collections.xqm
+++ b/src/vue-poc/features/collection/collections.xqm
@@ -5,45 +5,9 @@
:)
module namespace vue-api = 'quodatum:vue.api.collection';
import module namespace rest = "http://exquery.org/ns/restxq";
-import module namespace fw="quodatum:file.walker";
import module namespace ufile = 'vue-poc/file' at "../../lib/file.xqm";
declare namespace c="http://www.w3.org/ns/xproc-step";
-(:~ defines accessor functions for each collection type
-:)
-declare variable $vue-api:MODE:=map{
-"webfile":
- function($url)
- as element(c:directory)
- {
- let $path := ufile:web( $url)=>trace("vue-api:web ")
- return if( file:exists($path))then
- fw:directory-list($path,map{"max-depth":1,"include-info":true()})
- else
- error(xs:QName('vue-api:badpath'),$path)
- },
-"basexdb":
- function($url)
- as element(c:directory)
- {
- {
- if($url="/") then
- db:list()!
-
-
- else
- let $map:=vue-api:collection-next($url)
- for $name in map:keys($map)
- (: db:list-details($db as xs:string, $path as xs:string) as element(resource)* :)
- return if($map($name)="file") then
-
- else
-
- }
-}
-};
(:~
: history list
@@ -59,7 +23,7 @@ function vue-api:history( )
{$h!(<_ type="object">
{@url/string()}
- {@mode/string()}
+ {@mode/string()}
)}
@@ -70,18 +34,28 @@ function vue-api:history( )
: Returns folder info.
:)
declare
-%rest:path("/vue-poc/api/file")
+%rest:path("/vue-poc/api/collection")
%rest:query-param("url", "{$url}")
-%rest:query-param("protocol", "{$protocol}")
+%rest:query-param("protocol", "{$protocol}","webfile")
%rest:produces("application/json")
%output:method("json")
-function vue-api:file($url as xs:string,$protocol as xs:string?)
+function vue-api:file($url as xs:string,$protocol as xs:string)
as element(json)
{
- let $mode:=if(map:contains($vue-api:MODE,string($protocol)))then $protocol else "webfile"
- let $reader:=$vue-api:MODE($mode)
- let $items:=$reader($url)
- return
+ let $reader:=map{
+ "webfile":ufile:webfile#1,
+ "basexdb":ufile:basexdb#1
+ }
+ let $items:=$reader($protocol)($url)
+ return vue-api:items($items)
+};
+
+
+
+declare function vue-api:items($items)
+as element(json)
+{
+
{for $f in $items/c:directory
order by $f/@name/lower-case(.)
@@ -99,8 +73,8 @@ as element(json)
}
-};
-
+};
+
declare function vue-api:details($f as element(*),$icon as xs:string)
as element(*)*
{
@@ -112,23 +86,3 @@ as element(*)*
};
-(:~ return map of next level database contents
- :@param $url a database base collection e.g /dbname/fred/
-:)
-declare function vue-api:collection-next($url as xs:string)
-as map(*)
-{
- if(not(starts-with($url,"/")) or ends-with($url,"/")) then
- error(xs:QName('vue-api:badpath'),$url)
- else
- fold-left(
- uri-collection($url ),
- map{},
- function($acc,$this){
- let $s:=substring-after($this ,$url || "/")
- let $isDir:=contains($s,"/")
- let $s:=if($isDir)then substring-before($s,"/") else $s
- return map:merge((map:entry($s,if($isDir)then "directory" else "file"),$acc))
- }
- )
-};
diff --git a/src/vue-poc/features/collection/files.vue b/src/vue-poc/features/collection/files.vue
index bca070c..0328749 100644
--- a/src/vue-poc/features/collection/files.vue
+++ b/src/vue-poc/features/collection/files.vue
@@ -3,7 +3,7 @@
-
+
{{icon}}
@@ -16,7 +16,7 @@
+ hide-details single-line @keyup.native.enter="filter">
view_module
@@ -96,7 +96,7 @@
},
load(url){
this.busy=true
- HTTP.get("file",{params:{url:url,protocol:this.protocol}})
+ HTTP.get("collection",{params:{url:url,protocol:this.protocol}})
.then(r=>{
this.folders=r.data.folders
this.files=r.data.files
diff --git a/src/vue-poc/features/collection/history.vue b/src/vue-poc/features/collection/history.vue
index 174ef14..46f5b8b 100644
--- a/src/vue-poc/features/collection/history.vue
+++ b/src/vue-poc/features/collection/history.vue
@@ -4,7 +4,7 @@
- Example Chip
+ Example Chip
@@ -31,7 +31,7 @@
},
doEdit(item){
console.log("history: ",item)
- router.push({ path: 'edit', query: { url:item.url, mode:item.mode }})
+ router.push({ path: 'edit', query: { url:item.url, protocol:item.protocol }})
}
},
created:function(){
diff --git a/src/vue-poc/features/collection/history.xml b/src/vue-poc/features/collection/history.xml
index 2d7952b..5e33b52 100644
--- a/src/vue-poc/features/collection/history.xml
+++ b/src/vue-poc/features/collection/history.xml
@@ -9,5 +9,5 @@
-
+
\ No newline at end of file
diff --git a/src/vue-poc/features/edit/edit.vue b/src/vue-poc/features/edit/edit.vue
index cf8bac9..5c92705 100644
--- a/src/vue-poc/features/edit/edit.vue
+++ b/src/vue-poc/features/edit/edit.vue
@@ -9,7 +9,7 @@
- folder
+ {{icon}}
@@ -70,14 +70,14 @@
settings
- Show settings
+ Show settings
keyboard
- Show keyboard commands
+ Show keyboard commands
@@ -212,7 +212,8 @@ v-on:annotation="annotation">
})
},
showfiles(){
- router.push({ path: 'files', query: { url: this.path.join("/") }})
+ var target=this.protocol="basexdb"?"database":"files";
+ router.push({ path: target, query: { url: this.path.join("/"),protocol:this.protocol }})
},
beautify(){
this.busy=true
@@ -251,6 +252,11 @@ v-on:annotation="annotation">
if(this.dirty)event.preventDefault();
}
},
+ computed:{
+ icon(){
+ return (this.protocol=="basexdb")?"account_balance":"folder"
+ }
+ },
created(){
//https://forum.vuejs.org/t/detect-browser-close/5001/3 @fixme
document.addEventListener('beforeunload', this.leaving);
diff --git a/src/vue-poc/features/edit/edit.xqm b/src/vue-poc/features/edit/edit.xqm
index a4290a2..6a7b83c 100644
--- a/src/vue-poc/features/edit/edit.xqm
+++ b/src/vue-poc/features/edit/edit.xqm
@@ -18,22 +18,16 @@ declare namespace c="http://www.w3.org/ns/xproc-step";
declare
%rest:GET %rest:path("/vue-poc/api/edit")
%rest:query-param("url", "{$url}")
-%rest:query-param("protocol", "{$protocol}")
+%rest:query-param("protocol", "{$protocol}","webfile")
%rest:produces("application/json")
%output:method("json")
function vue-api:edit-get($url as xs:string,$protocol as xs:string)
{
- let $path := ufile:web( $url)=>trace("path ")
- return if( file:exists($path))then
- let $type:=mt:type($path)
- let $fetch:=mt:fetch-fn($type("treat-as"))
- return
- {$url}
- {$type?type}
- {$fetch($path)}
-
- else
- error(xs:QName('vue-api:raw'),$path)
+ let $reader := map{
+ "webfile":vue-api:get-webfile#1,
+ "basexdb":vue-api:get-basexdb#1
+ }
+ return $reader($protocol)($url)
};
(:~
@@ -61,3 +55,39 @@ function vue-api:edit-post($url as xs:string,$data)
error(xs:QName('vue-api:raw'),$path)
};
+(:~
+ : Returns a file content.
+ :)
+declare function vue-api:get-webfile($url as xs:string)
+as element(json)
+{
+ let $path := ufile:web( $url)=>trace("path ")
+ return if( file:exists($path))then
+ let $type:=mt:type($path)
+ let $fetch:=mt:fetch-fn($type("treat-as"))
+ return
+ {$url}
+ {$type?type}
+ {$fetch($path)}
+
+ else
+ error(xs:QName('vue-api:raw'),$url)
+};
+
+(:~
+ : Returns a file content.
+ :)
+declare function vue-api:get-basexdb($url as xs:string)
+as element(json)
+{
+ if( doc-available($url))then
+
+ let $doc:=doc($url)
+ return
+ {$url}
+ application/xml
+ {serialize($doc)}
+
+ else
+ error(xs:QName('vue-api:raw'),$url)
+};
\ No newline at end of file
diff --git a/src/vue-poc/features/images/images.vue b/src/vue-poc/features/images/images.vue
index ddcd127..0fb214b 100644
--- a/src/vue-poc/features/images/images.vue
+++ b/src/vue-poc/features/images/images.vue
@@ -1,13 +1,46 @@
+
- next
- {{page}}
- back
-
-
+
+
+
+
+
+
+
+ Cancel
+ Save
+
+
+
+
+ Clear
+
+ next
+ {{query.page}}
+ back
@@ -16,9 +49,9 @@
v-for="image in images"
:key="image.name"
>
-
+
-
+
favorite
@@ -35,6 +68,16 @@
+
+
+
+ {{selitem.name}}
+
+ highlight_off
+
+ blah blah
+
+
@@ -42,35 +85,56 @@
diff --git a/src/vue-poc/features/images/images.xqm b/src/vue-poc/features/images/images.xqm
index dfb38cd..d184afb 100644
--- a/src/vue-poc/features/images/images.xqm
+++ b/src/vue-poc/features/images/images.xqm
@@ -4,9 +4,8 @@
: @author Andy Bunce may-2017
:)
module namespace vue-api = 'quodatum:vue.api.images';
-import module namespace thb="expkg-zone58:image.thumbnailator";
-import module namespace rest = "http://exquery.org/ns/restxq";
import module namespace fw="quodatum:file.walker";
+import module namespace entity = 'quodatum.models.generated' at "../../models.gen.xqm";
declare namespace c="http://www.w3.org/ns/xproc-step";
declare variable $vue-api:PICS:="c:\tmp\";
@@ -18,33 +17,64 @@ declare
%rest:GET %rest:path("/vue-poc/api/images/list")
%rest:produces("application/json")
%rest:query-param("page", "{$page}",0)
+%rest:query-param("from", "{$from}")
+%rest:query-param("keyword", "{$keyword}")
%output:method("json")
-function vue-api:list( $page as xs:integer)
+function vue-api:list( $page as xs:integer,
+$from,
+$keyword
+)
{
+ let $a:=trace(($from,$keyword),"----------")
let $rowsPerPage:=24
- let $opt:=map{"include-filter":".*\.jpg",
- "max-depth":-1,
- "include-info":true()}
-let $d:= fw:directory-list($vue-api:PICS,$opt)
-let $f:=$d//c:file/@name/resolve-uri(encode-for-uri(.),base-uri(.))
-let $images:=subsequence($f,1+$rowsPerPage*$page,$rowsPerPage)
+ let $entity:=$entity:list("thumbnail")
+ let $images:=$entity("data")()
+ let $images:=if($from)then $images[datetaken ge $from] else $images
+ let $images:=if($keyword)then $images[keywords/keyword = $keyword] else $images
+ let $images:=subsequence($images,1+$rowsPerPage*$page,$rowsPerPage)
+
return
{
for $f in $images
return <_ type="object">
- {vue-api:get-image($f)}
+ {vue-api:get-image($f,$entity)}
}
};
+(:~
+ : keywords
+ :)
+declare
+%rest:GET %rest:path("/vue-poc/api/images/keywords")
+%rest:produces("application/json")
+%output:method("json")
+function vue-api:keywords()
+{
+let $keys:=
+collection("/vue-poc/Pictures")/image/keywords/keyword
+=>distinct-values()
+=>sort("http://www.w3.org/2005/xpath-functions/collation/html-ascii-case-insensitive")
+return
+ {
+ $keys!<_ >{.}
+ }
+
+};
-declare function vue-api:get-image($f as xs:string)
+declare function vue-api:get-image($image as element(image),$entity)
as element(*)*
{
- {$f}
- ,{fetch:binary($f)}
- ,{fetch:content-type($f)}
+let $id:=$entity?access?id($image)
+let $path:=$entity?access?path($image)
+let $name:=$entity?access?name($image)
+let $thumb:= $vue-api:PICS || $path
+let $thumb:=if(file:exists($thumb)) then $thumb else "C:\tmp\art.jpg"
+return ( {$id}
+ ,{$name}
+ ,{fetch:binary($thumb)}
+ ,{fetch:content-type($thumb)})
};
diff --git a/src/vue-poc/features/model.build/entity-gen.xqm b/src/vue-poc/features/model.build/entity-gen.xqm
new file mode 100644
index 0000000..cc78ef9
--- /dev/null
+++ b/src/vue-poc/features/model.build/entity-gen.xqm
@@ -0,0 +1,215 @@
+(:~
+ : generate xquery access code for entity definitions
+ :)
+module namespace bf = 'quodatum.tools.buildfields';
+declare default function namespace 'quodatum.tools.buildfields';
+declare namespace ent="https://github.com/Quodatum/app-doc/entity";
+
+(:~
+ : write generated xquery module from entity xml
+ : @param efolder full path to folder with entities e.g. fn:resolve-uri("./data/models")
+ : @param dest full name of xqm to create e.g. fn:resolve-uri("models.xqm")
+ :)
+declare %updating function write($efolder as xs:string,$dest as xs:string)
+{
+ let $src:=bf:module(bf:sources($efolder))
+ return file:write-text($dest,$src)
+};
+
+(:~
+ : generate xquery module for given entities as a string
+ :)
+declare function module($entities as element(ent:entity)*) as xs:string
+{
+let $src:= (: entity access maps
+ : auto generated from xml files in entities folder at: {fn:current-dateTime()}
+ :)
+
+module namespace entity = 'quodatum.models.generated';
+{bf:build-modules($entities)}
+{bf:build-namespaces($entities)}
+{( bf:build-describe($entities))}
+
+(:~ map of access functions for entity :)
+declare function entity:fields($entity as xs:string)
+as map(*){{
+ $entity:list($entity)("access")
+}};
+
+
+ return $src
+};
+
+(:~
+ : generate xquery for to return field value in the format: "name":function($_){}
+ :)
+declare function accessfn($f as element(ent:field)) as xs:string
+{
+let $type:=$f/@type/fn:string()
+return
+ "{$f/@name/fn:string()}": function($_ as element()) as {$type} {{$_/{$f/ent:xpath } }}
+};
+
+declare function generate($e as element(ent:entity)) as xs:string
+{
+ let $fields:=for $field in $e/ent:fields/ent:field
+ order by $field/@name
+ return $field
+
+ let $filter:=$e/ent:views/ent:view[@name="filter"]=>fn:tokenize()
+ let $filter:= $e/ent:fields/ent:field[@name=$filter]/ent:xpath/fn:concat("$item/",.)
+
+ return
+ "{$e/@name/fn:string()}": map{{
+ "name": "{ $e/@name/fn:string()}",
+ "description": "{ escape($e/ent:description)}",
+ "access": map{{ {$fields!accessfn(.)=>fn:string-join(",")} }},
+
+ "filter": function($item,$q) as xs:boolean{{
+ some $e in ( {fn:string-join($filter,", ")}) satisfies
+ fn:contains($e,$q, 'http://www.w3.org/2005/xpath-functions/collation/html-ascii-case-insensitive')
+ }},
+ "json": map{{ {$fields!jsonfn(.)=>fn:string-join(",")} }},
+
+ "data": function() as {$e/ent:data/@type/fn:string(.)}*
+ {{ {let $a:=$e/ent:data/fn:string() return if($a)then $a else "()"} }},
+
+ "views": map{{
+ {$e/ent:views/ent:view!("'" || @name || "': '" ||. || "'")=>fn:string-join(',')}
+ }}
+ }}
+};
+
+(:~
+ : @return sequence of element(entity) items for definitions at path
+ :)
+declare function sources($path as xs:string) as element(ent:entity)*
+{
+let $_:=fn:trace($path,"DD")
+ let $p:=fn:resolve-uri($path) || "/"
+ return for $f in file:list($p)
+ order by $f
+ return fn:doc(fn:concat($p,$f))/ent:entity
+};
+
+(:map for entity :)
+declare function build-map($entity as element(ent:entity)) as xs:string
+{
+let $m:=for $field in $entity/ent:fields/ent:field
+ order by $field/@name
+ return accessfn($field)
+return
+declare variable $entity:{$entity/@name/fn:string()}: map{{ {fn:string-join($m,",")}
+}};
+
+
+};
+
+(:~
+ : return xml for suitable json serialization for field
+:)
+declare function jsonfn($f as element(ent:field))
+as xs:string
+{
+ let $name:=$f/@name/fn:string()
+ let $type:=$f/@type/fn:string()
+ let $opt:=fn:contains($type,"?")
+ let $repeat:=fn:contains($type,"*")
+ let $json-type:=json-type($type)
+ let $mult:=if($repeat) then "*" else "?"
+
+ let $at:=if($json-type ne "string")
+ then "attribute type {'" || $json-type || "'},"
+ else ""
+ (: generate json xml :)
+ let $simple:=function() as xs:string{
+ (: {$type} :)
+ fn:data($_/{$f/ent:xpath })!element {$name} {{ {$at} .}}
+
+ }
+ let $array:=function() as xs:string{
+ (: array of strings :)
+ element {$name} {{
+ attribute type {{"array"}},
+ $_/{$f/ent:xpath }!element _ {{ attribute type {{"string"}}, .}}
+ }}
+
+ }
+ (: serialize when element :)
+ let $element:=function() as xs:string{
+ element {$name} {{
+ attribute type {{"string"}},
+ fn:serialize($_/{$f/ent:xpath})}}
+ }
+
+ return
+ "{$name}": function($_ as element()) as element({$name}){$mult} {{
+ {if($repeat)then
+ $array()
+ else if($type="element()") then
+ $element()
+ else $simple()} }}
+};
+
+
+(:~ convert xs type to json
+:)
+declare function json-type($xsd as xs:string) as xs:string{
+switch ($xsd)
+ case "element()" return "string"
+ case "xs:boolean" return "boolean"
+ case "xs:integer" return "number"
+ case "xs:float" return "number"
+ case "xs:double" return "number"
+ case "xs:string*" return "array"
+ default return "string"
+};
+
+(:~ declare any namespaces found :)
+declare function build-namespaces($entities as element()*){
+ for $n in distinct-deep($entities/ent:namespace)
+ return
+declare namespace {$n/@prefix/fn:string()}='{$n/@uri/fn:string()}';
+
+};
+(:~ declare any namespaces found :)
+declare function build-modules($entities as element()*){
+ for $n in distinct-deep($entities/ent:module)
+ return
+import module namespace {$n/@prefix/fn:string()}='{$n/@namespace/fn:string()}';
+
+};
+
+declare function build-describe($entities){
+ let $m:=for $e in $entities
+ return generate($e)
+ return
+declare variable $entity:list:=map {{ {fn:string-join($m,",")}
+}};
+
+
+};
+
+declare function escape($str as xs:string)
+as xs:string{
+ fn:replace(
+ fn:replace($str,'"','""'),
+ "'","''")
+};
+
+(:-----from functx-------------------:)
+
+ declare function distinct-deep
+ ( $nodes as node()* ) as node()* {
+
+ for $seq in (1 to fn:count($nodes))
+ return $nodes[$seq][fn:not(is-node-in-sequence-deep-equal(
+ .,$nodes[fn:position() < $seq]))]
+};
+
+declare function is-node-in-sequence-deep-equal
+ ( $node as node()? ,
+ $seq as node()* ) as xs:boolean {
+
+ some $nodeInSeq in $seq satisfies fn:deep-equal($nodeInSeq,$node)
+ } ;
\ No newline at end of file
diff --git a/src/vue-poc/features/model.build/model.vue b/src/vue-poc/features/model.build/model.vue
new file mode 100644
index 0000000..4cd4d50
--- /dev/null
+++ b/src/vue-poc/features/model.build/model.vue
@@ -0,0 +1,79 @@
+
+
+
+
+
+ Generate model.gen.xqm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{code}}
+
+
+
+
+
+
+
+ play_circle_outline
+ Run
+
+
+ {{ snackbar.msg }}
+ Close
+
+
+
+
+
+
diff --git a/src/vue-poc/features/model.build/rxq-model.xqm b/src/vue-poc/features/model.build/rxq-model.xqm
new file mode 100644
index 0000000..12947c7
--- /dev/null
+++ b/src/vue-poc/features/model.build/rxq-model.xqm
@@ -0,0 +1,27 @@
+(:~
+ : Update `generated/models.xqm` from files in `data/models`
+ : using file:///C:/Users/andy/workspace/app-doc/src/doc/data/doc/models
+ : $efolder:="file:///C:/Users/andy/workspace/app-doc/src/doc/data/doc/models"
+ : $target:="file:///C:/Users/andy/workspace/app-doc/src/doc/generated/models.xqm"
+ :)
+module namespace vue-api = 'quodatum:vue.api';
+
+import module namespace bf = 'quodatum.tools.buildfields' at "entity-gen.xqm";
+
+(:~
+ : Returns a file content.
+ :)
+declare
+%rest:POST %rest:path("/vue-poc/api/tasks/model")
+%rest:form-param("efolder", "{$efolder}")
+%rest:form-param("target", "{$target}")
+%rest:produces("application/json")
+%output:method("json")
+%updating
+function vue-api:model($efolder ,$target )
+{(
+ prof:variables(),
+ bf:write($efolder,$target),
+ db:output(Updated: {$target})
+)};
+
diff --git a/src/vue-poc/features/tasks.vue b/src/vue-poc/features/tasks.vue
index 16ba1f9..ffff5d6 100644
--- a/src/vue-poc/features/tasks.vue
+++ b/src/vue-poc/features/tasks.vue
@@ -2,6 +2,7 @@
Tasks
+ model
diff --git a/src/vue-poc/lib/entity-gen.xqm b/src/vue-poc/lib/entity-gen.xqm
new file mode 100644
index 0000000..cc78ef9
--- /dev/null
+++ b/src/vue-poc/lib/entity-gen.xqm
@@ -0,0 +1,215 @@
+(:~
+ : generate xquery access code for entity definitions
+ :)
+module namespace bf = 'quodatum.tools.buildfields';
+declare default function namespace 'quodatum.tools.buildfields';
+declare namespace ent="https://github.com/Quodatum/app-doc/entity";
+
+(:~
+ : write generated xquery module from entity xml
+ : @param efolder full path to folder with entities e.g. fn:resolve-uri("./data/models")
+ : @param dest full name of xqm to create e.g. fn:resolve-uri("models.xqm")
+ :)
+declare %updating function write($efolder as xs:string,$dest as xs:string)
+{
+ let $src:=bf:module(bf:sources($efolder))
+ return file:write-text($dest,$src)
+};
+
+(:~
+ : generate xquery module for given entities as a string
+ :)
+declare function module($entities as element(ent:entity)*) as xs:string
+{
+let $src:= (: entity access maps
+ : auto generated from xml files in entities folder at: {fn:current-dateTime()}
+ :)
+
+module namespace entity = 'quodatum.models.generated';
+{bf:build-modules($entities)}
+{bf:build-namespaces($entities)}
+{( bf:build-describe($entities))}
+
+(:~ map of access functions for entity :)
+declare function entity:fields($entity as xs:string)
+as map(*){{
+ $entity:list($entity)("access")
+}};
+
+
+ return $src
+};
+
+(:~
+ : generate xquery for to return field value in the format: "name":function($_){}
+ :)
+declare function accessfn($f as element(ent:field)) as xs:string
+{
+let $type:=$f/@type/fn:string()
+return
+ "{$f/@name/fn:string()}": function($_ as element()) as {$type} {{$_/{$f/ent:xpath } }}
+};
+
+declare function generate($e as element(ent:entity)) as xs:string
+{
+ let $fields:=for $field in $e/ent:fields/ent:field
+ order by $field/@name
+ return $field
+
+ let $filter:=$e/ent:views/ent:view[@name="filter"]=>fn:tokenize()
+ let $filter:= $e/ent:fields/ent:field[@name=$filter]/ent:xpath/fn:concat("$item/",.)
+
+ return
+ "{$e/@name/fn:string()}": map{{
+ "name": "{ $e/@name/fn:string()}",
+ "description": "{ escape($e/ent:description)}",
+ "access": map{{ {$fields!accessfn(.)=>fn:string-join(",")} }},
+
+ "filter": function($item,$q) as xs:boolean{{
+ some $e in ( {fn:string-join($filter,", ")}) satisfies
+ fn:contains($e,$q, 'http://www.w3.org/2005/xpath-functions/collation/html-ascii-case-insensitive')
+ }},
+ "json": map{{ {$fields!jsonfn(.)=>fn:string-join(",")} }},
+
+ "data": function() as {$e/ent:data/@type/fn:string(.)}*
+ {{ {let $a:=$e/ent:data/fn:string() return if($a)then $a else "()"} }},
+
+ "views": map{{
+ {$e/ent:views/ent:view!("'" || @name || "': '" ||. || "'")=>fn:string-join(',')}
+ }}
+ }}
+};
+
+(:~
+ : @return sequence of element(entity) items for definitions at path
+ :)
+declare function sources($path as xs:string) as element(ent:entity)*
+{
+let $_:=fn:trace($path,"DD")
+ let $p:=fn:resolve-uri($path) || "/"
+ return for $f in file:list($p)
+ order by $f
+ return fn:doc(fn:concat($p,$f))/ent:entity
+};
+
+(:map for entity :)
+declare function build-map($entity as element(ent:entity)) as xs:string
+{
+let $m:=for $field in $entity/ent:fields/ent:field
+ order by $field/@name
+ return accessfn($field)
+return
+declare variable $entity:{$entity/@name/fn:string()}: map{{ {fn:string-join($m,",")}
+}};
+
+
+};
+
+(:~
+ : return xml for suitable json serialization for field
+:)
+declare function jsonfn($f as element(ent:field))
+as xs:string
+{
+ let $name:=$f/@name/fn:string()
+ let $type:=$f/@type/fn:string()
+ let $opt:=fn:contains($type,"?")
+ let $repeat:=fn:contains($type,"*")
+ let $json-type:=json-type($type)
+ let $mult:=if($repeat) then "*" else "?"
+
+ let $at:=if($json-type ne "string")
+ then "attribute type {'" || $json-type || "'},"
+ else ""
+ (: generate json xml :)
+ let $simple:=function() as xs:string{
+ (: {$type} :)
+ fn:data($_/{$f/ent:xpath })!element {$name} {{ {$at} .}}
+
+ }
+ let $array:=function() as xs:string{
+ (: array of strings :)
+ element {$name} {{
+ attribute type {{"array"}},
+ $_/{$f/ent:xpath }!element _ {{ attribute type {{"string"}}, .}}
+ }}
+
+ }
+ (: serialize when element :)
+ let $element:=function() as xs:string{
+ element {$name} {{
+ attribute type {{"string"}},
+ fn:serialize($_/{$f/ent:xpath})}}
+ }
+
+ return
+ "{$name}": function($_ as element()) as element({$name}){$mult} {{
+ {if($repeat)then
+ $array()
+ else if($type="element()") then
+ $element()
+ else $simple()} }}
+};
+
+
+(:~ convert xs type to json
+:)
+declare function json-type($xsd as xs:string) as xs:string{
+switch ($xsd)
+ case "element()" return "string"
+ case "xs:boolean" return "boolean"
+ case "xs:integer" return "number"
+ case "xs:float" return "number"
+ case "xs:double" return "number"
+ case "xs:string*" return "array"
+ default return "string"
+};
+
+(:~ declare any namespaces found :)
+declare function build-namespaces($entities as element()*){
+ for $n in distinct-deep($entities/ent:namespace)
+ return
+declare namespace {$n/@prefix/fn:string()}='{$n/@uri/fn:string()}';
+
+};
+(:~ declare any namespaces found :)
+declare function build-modules($entities as element()*){
+ for $n in distinct-deep($entities/ent:module)
+ return
+import module namespace {$n/@prefix/fn:string()}='{$n/@namespace/fn:string()}';
+
+};
+
+declare function build-describe($entities){
+ let $m:=for $e in $entities
+ return generate($e)
+ return
+declare variable $entity:list:=map {{ {fn:string-join($m,",")}
+}};
+
+
+};
+
+declare function escape($str as xs:string)
+as xs:string{
+ fn:replace(
+ fn:replace($str,'"','""'),
+ "'","''")
+};
+
+(:-----from functx-------------------:)
+
+ declare function distinct-deep
+ ( $nodes as node()* ) as node()* {
+
+ for $seq in (1 to fn:count($nodes))
+ return $nodes[$seq][fn:not(is-node-in-sequence-deep-equal(
+ .,$nodes[fn:position() < $seq]))]
+};
+
+declare function is-node-in-sequence-deep-equal
+ ( $node as node()? ,
+ $seq as node()* ) as xs:boolean {
+
+ some $nodeInSeq in $seq satisfies fn:deep-equal($nodeInSeq,$node)
+ } ;
\ No newline at end of file
diff --git a/src/vue-poc/lib/file.xqm b/src/vue-poc/lib/file.xqm
index 1b75a4c..dcb1126 100644
--- a/src/vue-poc/lib/file.xqm
+++ b/src/vue-poc/lib/file.xqm
@@ -4,7 +4,8 @@
: @author Andy Bunce, 2017
:)
module namespace ufile = 'vue-poc/file';
-
+import module namespace fw="quodatum:file.walker";
+declare namespace c="http://www.w3.org/ns/xproc-step";
(:~
: resolve path relative to basex webpath
: file("/fred")=>C:\Program Files (x86)\BaseX\webapp\fred
@@ -21,3 +22,54 @@ as xs:string
return file:resolve-path($file,$webroot)
};
+declare function ufile:webfile($url as xs:string)
+as element(c:directory)
+{
+ let $path := ufile:web( $url)=>trace("vue-api:web ")
+ return if( file:exists($path))then
+ fw:directory-list($path,map{"max-depth":1,"include-info":true()})
+ else
+ error(xs:QName('ufile:badpath'),$path)
+};
+
+declare function ufile:basexdb($url as xs:string)
+as element(c:directory)
+{
+ {
+ if($url="/") then
+ db:list()!
+
+
+ else
+ let $map:=ufile:collection-next($url)
+ for $name in map:keys($map)
+ (: db:list-details($db as xs:string, $path as xs:string) as element(resource)* :)
+ return if($map($name)="file") then
+
+ else
+
+ }
+};
+
+(:~ return map of next level database contents
+ :@param $url a database base collection e.g /dbname/fred/
+:)
+declare function ufile:collection-next($url as xs:string)
+as map(*)
+{
+ if(not(starts-with($url,"/")) or ends-with($url,"/")) then
+ error(xs:QName('ufile:badcollection'),$url)
+ else
+ fold-left(
+ uri-collection($url ),
+ map{},
+ function($acc,$this){
+ let $s:=substring-after($this ,$url || "/")
+ let $isDir:=contains($s,"/")
+ let $s:=if($isDir)then substring-before($s,"/") else $s
+ return map:merge((map:entry($s,if($isDir)then "directory" else "file"),$acc))
+ }
+ )
+};
diff --git a/src/vue-poc/models.gen.xqm b/src/vue-poc/models.gen.xqm
new file mode 100644
index 0000000..8bdcc51
--- /dev/null
+++ b/src/vue-poc/models.gen.xqm
@@ -0,0 +1,56 @@
+(: entity access maps
+ : auto generated from xml files in entities folder at: 2017-07-17T17:47:26.588+01:00
+ :)
+
+module namespace entity = 'quodatum.models.generated';
+declare namespace c='http://www.w3.org/ns/xproc-step';
+
+declare variable $entity:list:=map {
+ "thumbnail": map{
+ "name": "thumbnail",
+ "description": "an image.",
+ "access": map{
+ "id": function($_ as element()) as xs:integer {$_/db:node-id(.) },
+ "name": function($_ as element()) as xs:string {$_/file/@name },
+ "path": function($_ as element()) as xs:string {$_/file/@path },
+ "size": function($_ as element()) as xs:integer {$_/0 } },
+
+ "filter": function($item,$q) as xs:boolean{
+ some $e in ( $item/file/@name) satisfies
+ fn:contains($e,$q, 'http://www.w3.org/2005/xpath-functions/collation/html-ascii-case-insensitive')
+ },
+ "json": map{
+ "id": function($_ as element()) as element(id)? {
+ (: xs:integer :)
+ fn:data($_/db:node-id(.))!element id { attribute type {'number'}, .}
+ },
+ "name": function($_ as element()) as element(name)? {
+ (: xs:string :)
+ fn:data($_/file/@name)!element name { .}
+ },
+ "path": function($_ as element()) as element(path)? {
+ (: xs:string :)
+ fn:data($_/file/@path)!element path { .}
+ },
+ "size": function($_ as element()) as element(size)? {
+ (: xs:integer :)
+ fn:data($_/0)!element size { attribute type {'number'}, .}
+ } },
+
+ "data": function() as element(image)*
+ { collection("/vue-poc/Pictures")/image },
+
+ "views": map{
+ 'filter': 'name'
+ }
+ }
+};
+
+
+
+(:~ map of access functions for entity :)
+declare function entity:fields($entity as xs:string)
+as map(*){
+ $entity:list($entity)("access")
+};
+
\ No newline at end of file
diff --git a/src/vue-poc/models/thumbnail.xml b/src/vue-poc/models/thumbnail.xml
index 532b6fe..44a4372 100644
--- a/src/vue-poc/models/thumbnail.xml
+++ b/src/vue-poc/models/thumbnail.xml
@@ -1,15 +1,22 @@
an image.
-
+
+ Database Id.
+ db:node-id(.)
+
File name.
- @name
+ file/@name
+
+ File path. e.g. Pictures/2012/2012-06-23/skating.jpg
+ file/@path
+
file size.
- @size
+ 0
@@ -17,6 +24,6 @@
name
fa fa-file
- doc("/vue-poc/pics.xml")//c:file
+ collection("/vue-poc/Pictures")/image
\ No newline at end of file
diff --git a/src/vue-poc/static/app-gen.js b/src/vue-poc/static/app-gen.js
index 20a4ecc..2b9024a 100644
--- a/src/vue-poc/static/app-gen.js
+++ b/src/vue-poc/static/app-gen.js
@@ -1,4 +1,4 @@
-// generated 2017-07-12T11:37:10.722+01:00
+// generated 2017-07-17T17:49:54.864+01:00
Vue.component('my-component',{template:`
{{href}}link
`,
@@ -36,9 +36,7 @@
{{ item.model ? 'keyboard_arrow_up' : 'keyboard_arrow_down' }}
-
-
-
+
@@ -157,7 +155,7 @@ v0.0.2
-
+
{{icon}}
@@ -169,7 +167,7 @@ v0.0.2
{{ url }}
-
+
view_module
@@ -248,7 +246,7 @@ v0.0.2
},
load(url){
this.busy=true
- HTTP.get("file",{params:{url:url,protocol:this.protocol}})
+ HTTP.get("collection",{params:{url:url,protocol:this.protocol}})
.then(r=>{
this.folders=r.data.folders
this.files=r.data.files
@@ -311,7 +309,7 @@ v0.0.2
- Example Chip
+ Example Chip
@@ -337,7 +335,7 @@ v0.0.2
},
doEdit(item){
console.log("history: ",item)
- router.push({ path: 'edit', query: { url:item.url, mode:item.mode }})
+ router.push({ path: 'edit', query: { url:item.url, protocol:item.protocol }})
}
},
created:function(){
@@ -357,7 +355,7 @@ v0.0.2
- folder
+ {{icon}}
@@ -416,14 +414,14 @@ v0.0.2
settings
- Show settings
+ Show settings
keyboard
- Show keyboard commands
+ Show keyboard commands
@@ -555,7 +553,8 @@ v0.0.2
})
},
showfiles(){
- router.push({ path: 'files', query: { url: this.path.join("/") }})
+ var target=this.protocol="basexdb"?"database":"files";
+ router.push({ path: target, query: { url: this.path.join("/"),protocol:this.protocol }})
},
beautify(){
this.busy=true
@@ -594,6 +593,11 @@ v0.0.2
if(this.dirty)event.preventDefault();
}
},
+ computed:{
+ icon(){
+ return (this.protocol=="basexdb")?"account_balance":"folder"
+ }
+ },
created(){
//https://forum.vuejs.org/t/detect-browser-close/5001/3 @fixme
document.addEventListener('beforeunload', this.leaving);
@@ -788,18 +792,31 @@ v0.0.2
- next
- {{page}}
- back
-
-
+
+
+
+
+
+
+
+ Cancel
+ Save
+
+
+
+
+ Clear
+
+ next
+ {{query.page}}
+ back
-
+
-
+
favorite
@@ -816,41 +833,72 @@ v0.0.2
+
+
+
+ {{selitem.name}}
+
+ highlight_off
+
+ blah blah
+
+
`,
data: () => ({
images:[],
- page:0
+ query:{page:0, // current page
+ from:null,
+ keyword:null
+ },
+ modal:false, // showing datepicker
+
+ keywords:[],
+ showInfo:false,
+ selitem:"TODO"
}),
methods:{
src(item){
- //return "https://unsplash.it/150/300?image="+Math.floor(Math.random() * 100) + 1
return "data:image/jpeg;base64,"+item.data
},
getImages(){
- HTTP.get("images/list?page="+this.page)
+ HTTP.get("images/list",{params:this.query})
.then(r=>{
this.images=r.data.items
- })
-
+ })
},
- selected(){
- alert("not yet")
+ clear(){
+ this.query.from=null;
+ this.query.keyword=null;
+ },
+ selected(image){
+ this.selitem=image;
+ this.showInfo=true;
}
+
},
watch:{
- page(v){
- this.$router.push({ query: { page: this.page }})
+ "query":{
+ handler:function(v){
+ this.$router.push({ query: this.query })
+ },
+ deep:true
},
$route(v){
this.getImages()
}
},
created:function(){
- this.page=this.$route.query.page || this.page
+ this.query.page=Number(this.$route.query.page) || this.query.page
+ this.query.keyword=this.$route.query.keyword || this.query.keyword
+ this.query.from=this.$route.query.from || this.query.from
this.getImages()
+ HTTP.get("images/keywords")
+ .then(r=>{
+ this.keywords=r.data.items
+ })
}
}
@@ -1015,6 +1063,75 @@ v0.0.2
}
}
+ );
+ const Model=Vue.extend({template:`
+
+
+
+ Generate model.gen.xqm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{code}}
+
+
+
+
+
+
+
+ play_circle_outline
+ Run
+
+
+ {{ snackbar.msg }}
+ Close
+
+
+
+ `,
+
+ data: function(){
+ return {
+ params:{
+ efolder:"C:/Users/andy/git/vue-poc/src/vue-poc/models",
+ target:"C:/Users/andy/git/vue-poc/src/vue-poc/models.gen.xqm"
+ },
+ waiting:false,
+ snackbar:{show:false,msg:"",context:"success"},
+ }
+ },
+ methods:{
+ submit(){
+ this.waiting=true
+ HTTP.post("tasks/model",Qs.stringify(this.params))
+ .then(r=>{
+ this.waiting=false
+ this.snackbar={show:true,msg:r.data.msg,context:"success"}
+ console.log(r.data)
+ })
+ .catch(error=>{
+ this.waiting=false
+ this.snackbar={show:true,msg:"Problem",context:"error"}
+ console.log(error);
+ });
+ }
+ },
+ computed:{
+ code(){return 'import module namespace entity = "quodatum.models.generated" at "'+this.params.target+'";'}
+ }
+}
+
);
const People=Vue.extend({template:`
@@ -1493,6 +1610,7 @@ v0.0.2
const Task=Vue.extend({template:`
Tasks
+ model
`,
@@ -1633,6 +1751,7 @@ const router = new VueRouter({
{ path: '/eval', component: Eval,meta:{title:"Evaluate XQuery"} },
{ path: '/logs', component: Log,meta:{title:"Server logs"} },
{ path: '/tasks', component: Task,meta:{title:"Runnable tasks"} },
+ { path: '/tasks/model', component: Model,meta:{title:"build model"} },
{ path: '/jobs', component: Job,meta:{title:"Jobs"} },
{ path: '*', component: Notfound,meta:{title:"Page not found"} }
],
@@ -1673,42 +1792,42 @@ const app = new Vue({
text: 'Collections' ,
model: false,
children: [
- {href: 'database', text: 'Databases',icon: 'account_balance' },
- {href: 'files', text: 'File system',icon: 'folder' },
- {href: 'edit',text: 'edit',icon: 'mode_edit'},
- {href: 'history',text: 'history',icon: 'history'},
- {href: 'logs',text: 'Server logs',icon: 'dns'}
+ {href: '/database', text: 'Databases',icon: 'account_balance' },
+ {href: '/files', text: 'File system',icon: 'folder' },
+ {href: '/edit',text: 'edit',icon: 'mode_edit'},
+ {href: '/history',text: 'history',icon: 'history'},
+ {href: '/logs',text: 'Server logs',icon: 'dns'}
]},
{
icon: 'directions_run',
text: 'Actions' ,
model: false,
children: [
- {href: 'eval',text: 'Query',icon: 'play_circle_outline'},
- {href: 'jobs',text: 'Running jobs',icon: 'dashboard'},
- {href: 'tasks',text: 'Tasks',icon: 'history'},
+ {href: '/eval',text: 'Query',icon: 'play_circle_outline'},
+ {href: '/jobs',text: 'Running jobs',icon: 'dashboard'},
+ {href: '/tasks',text: 'Tasks',icon: 'history'}
]},
{
icon: 'more_horiz',
text: 'More' ,
model: false,
children: [
- {href: 'people',text: 'People',icon: 'person'},
- {href: 'select',text: 'select',icon: 'extension'},
- {href: 'puzzle',text: 'Puzzle',icon: 'extension'},
- {href: 'images',text: 'Images',icon: 'camera_roll'},
- {href: 'tabs',text: 'tabs',icon: 'switch_camera'},
- {href: 'ping',text: 'ping',icon: 'update'},
- {href: 'thumbnail',text: 'thumbnail',icon: 'touch_app'}
+ {href: '/people',text: 'People',icon: 'person'},
+ {href: '/select',text: 'select',icon: 'extension'},
+ {href: '/puzzle',text: 'Puzzle',icon: 'extension'},
+ {href: '/images',text: 'Images',icon: 'camera_roll'},
+ {href: '/tabs',text: 'tabs',icon: 'switch_camera'},
+ {href: '/ping',text: 'ping',icon: 'update'},
+ {href: '/thumbnail',text: 'thumbnail',icon: 'touch_app'}
]},
- {href: 'settings',text: 'settings',icon: 'settings' }
+ {href: '/settings',text: 'settings',icon: 'settings' }
]
}},
methods: {
search(){
- this.$router.push({path: 'search',query: { q: this.q }})
+ this.$router.push({path: '/search',query: { q: this.q }})
},
logout(){
HTTP.get("logout").then(r=>{
diff --git a/src/vue-poc/static/app.html b/src/vue-poc/static/app.html
index 72a6dc7..3b5990b 100644
--- a/src/vue-poc/static/app.html
+++ b/src/vue-poc/static/app.html
@@ -9,17 +9,17 @@
Vue Router Test
-
+
-
+
-
+
diff --git a/src/vue-poc/tasks/createimage.xq b/src/vue-poc/tasks/createimage.xq
new file mode 100644
index 0000000..bdafb9a
--- /dev/null
+++ b/src/vue-poc/tasks/createimage.xq
@@ -0,0 +1,15 @@
+(:~ generate image docs from meta docs 52 sec :)
+import module namespace metadata = 'expkg-zone58:image.metadata';
+
+for $meta in collection("/vue-poc/Pictures")/metadata
+ let $loc:=db:path($meta)=>tokenize("/")
+ let $name:=$loc[count($loc)-1]
+ let $path:= subsequence($loc,1,count($loc)-1)=>string-join("/")
+ let $image:=
+ {
+ metadata:core($meta),
+ metadata:geo($meta),
+ metadata:keywords($meta)
+ }
+let $target:=$path || "/image.xml"
+return db:replace("vue-poc",$target,$image)
\ No newline at end of file
diff --git a/src/vue-poc/tasks/generate-model-local.xq b/src/vue-poc/tasks/generate-model-local.xq
new file mode 100644
index 0000000..a0f7d0d
--- /dev/null
+++ b/src/vue-poc/tasks/generate-model-local.xq
@@ -0,0 +1,12 @@
+(:~
+ : Update `generated/models.xqm` from files in `data/models`
+ : using file:///C:/Users/andy/workspace/app-doc/src/doc/data/doc/models
+ :)
+
+declare namespace task="https://github.com/Quodatum/app-doc/task";
+import module namespace bf = 'quodatum.tools.buildfields' at "../lib/entity-gen.xqm";
+
+let $efolder:="file:///C:/Users/andy/workspace/app-doc/src/doc/data/doc/models"
+let $target:="file:///C:/Users/andy/workspace/app-doc/src/doc/generated/models.xqm"
+return (bf:write($efolder,$target),db:output("generated C:/Users/andy/workspace/app-doc/src/doc/generated/models.xqm"))
+
diff --git a/tools/compile.xq b/tools/compile.xq
index c652ec4..5265c4f 100644
--- a/tools/compile.xq
+++ b/tools/compile.xq
@@ -1,5 +1,5 @@
(:~
- : create app.js from vue files
+ : create app-gen.js from vue files
:)
import module namespace html5="text.html5" at "html5parse.xqm";
import module namespace fw="quodatum:file.walker";