XQuery idiom return() - xquery

Why do I see return() at the end of an XQuery query?
e.g.
let $updateIssues:=
for $issue in fn:collection("InProgress_Audit")/ProductIssue
return local:UpdateIssue($issue)
return ()

It's not entirely clear what your question is. Given the way you've formulated it, possible answers include:
You see it because it's there.
You see it because someone typed it when they wrote the query.
Perhaps you mean 'why is it there?' Possible answers include:
It's there because without a return clause the FLWOR expression begun by the let clause is not complete.
It's there because the author of this query has a quirky sense of humor, and thought a four-line query was an amusing way to write an expression denoting the empty sequence (which can be more concisely written ()).
It's there because the author of the query wants you as a reader to know he'd really rather be writing C or Java or, really, any other programming language.
It's there because the author of the query finds it amusing that the return keyword in XQuery can be written to look like a function call. (The author may enjoy hazing newbies and practical jokes, too; approach with caution.)
Perhaps you mean "what does this query mean and how does it mean it?" Possible answers include:
The query returns the empty sequence.
The query takes the form of a FLWOR expression which defines a binding for the variable updateIssues (whose value is given by a nested FLWOR expression), and then returns () (that is, the empty sequence). Since nothing in the return clause depends on the value of updateIssues, there is no need for an XQuery engine to evaluate the expression used to specify the value (but there is also no guarantee that it won't do so -- processors are allowed to be smart about optimization but not required to be).

In your example, the return () expression is the body of your let expression.
The assignment to $updateIssues is walking through a bunch of nodes, returning the value from a call to local:UpdateIssue(), and the sequence of those return values is being used as the variable value.
But, then, nothing is done with the variable and the function simply returns nothing to its caller.
I would be worried that an optimizing processor may choose to throw out the assignment because the variable being assigned isn't being used anywhere, but the processor you are using is likely not doing that if you are getting the update results you are expecting.
So, all that last line is doing is always returning an empty sequence as the value of the function when called.

If I get your question right you are asking about return ().
return () means that you are returning a blank so in short you just want to assign the global variable to something and do not want to return anything from the function.
Else if you want to know the details on Return expression. It is a Part of XQuery FLWOR Expressions.
Being a functional language XQuery works on Functions.
For Loop, Let Loop, Where, Order By (FLWO) are all internally (inside XQuery Engine) acting as functions. Thus they all require a return after call to specify what needs to be the output from them.
If you require more information on XQuery functions you may refer the offical documentation.

Related

Why do we use [1] behind an order by clause in xquery expressions?

SELECT xText.query (' let $planes := /planes/plane
return <results>
{
for $x in $planes
where $x/year >= 1970
order by ($x/year)[1]
return ($x/make, $x/model,$x/year )
}
</results>
')
FROM planes
In this code, what is the purpose of [1] in line order by ($x/year)[1]
I have tried to execute this code without using [1] behind order by clause. Then this error has occurred.
XQuery [planes.xtext.query()]: 'order by' requires a singleton (or empty sequence), found operand of type 'xtd:untypedAtomic*'
XQuery 1.0 defined an option called "static type checking": if this option is in force, you need to write queries in such a way that the compiler can tell in advance ("statically") that the result will not be a type error. The operand of "order by" needs to be a singleton, and with static type checking in force, the compiler needs to be able to verify that it will be a singleton, which is why the [1] has been added. It would have been better to write exactly-one($x/year) because this doesn't only keep the compiler happy, it also demands a run-time check that $x/year is actually a singleton.
Very few XQuery vendors chose to implement static type checking, for very good reasons in my view: it makes queries harder to write, and it actually encourages you to write things like this example that do LESS checking than a system without this "feature".
In fact, as far as I know the only mainstream (non-academic) implementation that does static type checking is Microsoft's SQL Server.
Static type checking should not be confused with optimistic type checking where the compiler tells you about things that are bound to fail, but defers checking until run-time for things that might or might not be correct.
Actually the above is a bit of a guess. It's also possible that some <plane> elements have more than one child called <year>, and that you want to sort on the first of these. That would justify the [1] even on products that don't do static type checking.
The [1] is a predicate that is selecting the first item in the sequence. It is equivalent to the expression [position() = 1]. A predicate in XPath acts kind of like a WHERE clause in SQL. The filter is applied, and anything that returns true is selected, the things that return false are not.
When you don't apply the predicate, you get the error. That error is saying that the order by expects a single item, or nothing (an empty sequence).
At least one of the plane has multiple year, so the predicate ensures that only the first one is used for the order by expression.

Why I cannot get exactly the same GString as was put to map in Groovy?

With the following snippet I cannot retrieve gString from a map:
def contents = "contents"
def gString = "$contents"
def map = [(gString): true]
assert map.size() == 1 // Passes
assert gString.hashCode() == map.keySet().first().hashCode() // Passes, same hash code
assert gString.is(map.keySet().first()) // Passes, exactly the same object
assert map[gString] // Fails
How is that possible?
What's interesting here is that map.get(map.keySet()[0]) works fine while map.get[map.keySet()[0]] does not.
Assertion message clearly shows that there's something wrong:
assert map[gString] // Fails
| ||
| |contents
| null
[contents:true]
It's not the same question as Why groovy does not see some values in dictionary?
First answer there suggests:
You're adding GString instances as keys in your map, then searching for them using String instances.
In this question I clearly add GString and try to retrieve GString.
Also neither Why are there different behaviors for the ways of addressing GString keys in maps? nor Groovy different results on using equals() and == on a GStringImpl have an answer for me. I do not mutate anything and I do not mix String with GString. Groovy documentation is not helpful as well.
tl;dr: You seem to have discovered a bug in Groovy's runtime argument overloading evaluation.
Answer:
map[gString] is evaluated as map.getAt(gString) at runtime straightforwardly via Groovy's operator overloading mechanism. So far, so good, but now is where everything starts to go awry. The Java LinkedHashMap class does not have a getAt method anywhere in it's type hierarchy, so Groovy must use dynamically associated mixin methods instead (Actually that statement is sort of reversed. Groovy uses mixin methods before using the declared methods in the class hierarchy.)
So, to make a long story short, Groovy resolves map.getAt(gString) to use the category method DefaultGroovyMethods.getAt(). Easy-peasy, right? Except that this method has a large number of different argument overloads, several of which might apply, especially when you take Groovy's default argument coercion into account.
Unfortunately, instead of choosing DefaultGroovyMethods.getAt(Map<K,V>,K), which would seem to be a perfect match, Groovy chooses DefaultGroovyMethods.getAt(Object,String), which coerces the GString key argument into a String. Since the actual key is in fact a GString, the method ultimately fails to find the value.
To me the real killer is that if the argument overload resolution is performed directly from code (instead of after the operator resolution and the category method selection), then Groovy makes the right overload choice! That is to say, if you replace this expression:
map[gString]
with this expression:
DefaultGroovyMethods.getAt(map,gString)
then the argument overloading is resolved correctly, and the correct value is found and returned.

Having trouble understanding FLWOR expressions combined with inserts and return statements [duplicate]

I recognized that (insert/delete)-XQueries executed with the BaseX client always returning an empty string. I find this very confusing or unintuitive.
Is there a way to find out if the query was "successful" without querying the database again (and using potentially buggy "transitive" logic like "if I deleted a node, there must be 'oldNodeCount-1' nodes in the XML")?
XQuery Update statements do not return anything -- that's how they are defined. But you're not the only one who does not like those restrictions, and BaseX added two ways around this limitation:
Returning Results
By default, it is not possible to mix different types of expressions
in a query result. The outermost expression of a query must either be
a collection of updating or non-updating expressions. But there are
two ways out:
The BaseX-specific update:output() function bridges this gap: it caches the results of its arguments at runtime and returns them after
all updates have been processed. The following example performs an
update and returns a success message:
update:output("Update successful."), insert node <c/> into doc('factbook')/mondial
With the MIXUPDATES option, all updating constraints will be turned off. Returned nodes will be copied before they are modified by
updating expressions. An error is raised if items are returned within
a transform expression.
If you want to modify nodes in main memory, you can use the transform
expression.
The transform expression will not help you, as you seem to modify the data on disk. Enabling MIXUPDATES allows you to both update the document and return something at the same time, for example running something like
let $node := <c/>
return ($node, insert node $node into doc('factbook')/mondial)
MIXUPDATES allows you to return something which can be further processed. Results are copied before being returned, if you run multiple updates operations and do not get the expected results, make sure you got the concept of the pending update list.
The db:output() function intentionally breaks its interface contract: it is defined to be an updating function (not having any output), but at the same time it prints some information to the query info. You cannot further process these results, but the output can help you debugging some issues.
Pending Update List
Both ways, you will not be able to have an immediate result from the update, you have to add something on your own -- and be aware updates are not visible until the pending update list is applied, ie. after the query finished.
Compatibility
Obviously, these options are BaseX-specific. If you strongly require compatible and standard XQuery, you cannot use these expressions.

How to return results together with update operations in BaseX?

I recognized that (insert/delete)-XQueries executed with the BaseX client always returning an empty string. I find this very confusing or unintuitive.
Is there a way to find out if the query was "successful" without querying the database again (and using potentially buggy "transitive" logic like "if I deleted a node, there must be 'oldNodeCount-1' nodes in the XML")?
XQuery Update statements do not return anything -- that's how they are defined. But you're not the only one who does not like those restrictions, and BaseX added two ways around this limitation:
Returning Results
By default, it is not possible to mix different types of expressions
in a query result. The outermost expression of a query must either be
a collection of updating or non-updating expressions. But there are
two ways out:
The BaseX-specific update:output() function bridges this gap: it caches the results of its arguments at runtime and returns them after
all updates have been processed. The following example performs an
update and returns a success message:
update:output("Update successful."), insert node <c/> into doc('factbook')/mondial
With the MIXUPDATES option, all updating constraints will be turned off. Returned nodes will be copied before they are modified by
updating expressions. An error is raised if items are returned within
a transform expression.
If you want to modify nodes in main memory, you can use the transform
expression.
The transform expression will not help you, as you seem to modify the data on disk. Enabling MIXUPDATES allows you to both update the document and return something at the same time, for example running something like
let $node := <c/>
return ($node, insert node $node into doc('factbook')/mondial)
MIXUPDATES allows you to return something which can be further processed. Results are copied before being returned, if you run multiple updates operations and do not get the expected results, make sure you got the concept of the pending update list.
The db:output() function intentionally breaks its interface contract: it is defined to be an updating function (not having any output), but at the same time it prints some information to the query info. You cannot further process these results, but the output can help you debugging some issues.
Pending Update List
Both ways, you will not be able to have an immediate result from the update, you have to add something on your own -- and be aware updates are not visible until the pending update list is applied, ie. after the query finished.
Compatibility
Obviously, these options are BaseX-specific. If you strongly require compatible and standard XQuery, you cannot use these expressions.

xquery call a maintenance function within another function

Using MarkLogic Xquery, I have a function (admin:add-collection-to-publication) which calls another maintenance function ( admin:check-collections-exists) which checks for an element's presence and if its not present then it creates that particular element.
The way I call the maintenance function is with a let. This seems like a weird way, to do this it requires creating an unused variable. Should I instead return a sequence with the call to admin:check-collections-exists being the first item in the sequence then the subsequent processing being the second element? Just looking for the standard elegant way to do this. My functions are:
declare function admin:add-collection-to-publication($pub-name, $collection-name)
{
(:does this publication have a COLLECTIONS element?:)
let $unnecessary-variable := admin:check-collections-exists($pub-name)
(:now go and do what this function does:)
return "do some other stuff then return"
};
declare function admin:check-collections-exists($pub-name)
{
if(fn:exists($pubs-node/pub:PUBLICATION[pub:NAME/text()=$pub-name]/pub:COLLECTIONS))
then
"exists"
else
xdmp:node-insert-child($pubs-node/pub:PUBLICATION[pub:NAME/text()=$pub-name],<pub:COLLECTIONS/>)
};
Using a sequence is not reliable. MarkLogic will most likely attempt to evaluate the sequence items in parallel, which could cause the creating to happen at 'same' time or even after the other work. The best approach is indeed to use a let. The let's are always evaluated before the return. Note though that let's can be evaluated in parallel as well, but the optimizer is smart enough to detect dependencies.
Personally, I often use unused variables. For example to insert logging statements, in which case I have one unused variable name that I reuse each time:
let $log := xdmp:log($before)
let $result := do:something($before)
let $log := xdmp:log($result)
You could also use a very short variable name like $_. Or you could reconsider actually giving the variable a sensible name, and use it after all, even though you know it never reaches the else
let $exists :=
if (collection-exists()) then
create()
else true()
return
if ($exists) then
"do stuff"
else () (: never reached!! :)
HTH!

Resources