Nesting expressions in Wiremock - jsonpath

I am trying to nest expressions in Wiremock and I get an error. Is it possible to nest a randomValue inside the pickRandom helper?
Example:
I have a wiremock stub that returns: "{{{pickRandom '{\"test\": \"1\"}' '{\"test\": \"{{randomValue type=\'UUID\'}}\"}'}}}"

I cannot test this but it might be possible to select the pickRandom Helper value from a list passed as a parameter, e.g.: {{{pickRandom (jsonPath request.body '$.names')}}}
{{{pickRandom ('{\"test\": \"1\"}' '{\"test\": \"{{randomValue type=\'UUID\'}}\"}')}}}
Ref: http://wiremock.org/docs/response-templating/

Related

How do I get information about function calls from a Lua script?

I have a script written in Lua 5.1 that imports third-party module and calls some functions from it. I would like to get a list of function calls from a module with their arguments (when they are known before execution).
So, I need to write another script which takes the source code of my first script, parses it, and extracts information from its code.
Consider the minimal example.
I have the following module:
local mod = {}
function mod.foo(a, ...)
print(a, ...)
end
return mod
And the following driver code:
local M = require "mod"
M.foo('a', 1)
M.foo('b')
What is the better way to retrieve the data with the "use" occurrences of the M.foo function?
Ideally, I would like to get the information with the name of the function being called and the values of its arguments. From the example code above, it would be enough to get the mapping like this: {'foo': [('a', 1), ('b')]}.
I'm not sure if Lua has functions for reflection to retrieve this information. So probably I'll need to use one of the existing parsers for Lua to get the complete AST and find the function calls I'm interested in.
Any other suggestions?
If you can not modify the files, you can read the files into a strings then parse mod file and find all functions in it, then use that information to parse the target file for all uses of the mod library
functions = {}
for func in modFile:gmatch("function mod%.(%w+)") do
functions[func] = {}
end
for func, call in targetFile:gmatch("M%.(%w+)%(([^%)]+)%)") do
args = {}
for arg in string.gmatch(call, "([^,]+)") do
table.insert(args, arg)
end
table.insert(functions[func], args)
end
Resulting table can then be serialized
['foo'] = {{"'a'", " 1"}, {"'b'"}}
3 possible gotchas:
M is not a very unique name and could vary possibly match unintended function calls to another library.
This example does not handle if there is a function call made inside the arg list. e.g. myfunc(getStuff(), true)
The resulting table does not know the typing of the args so they are all save as strings representations.
If modifying the target file is an option you can create a wrapper around your required module
function log(mod)
local calls = {}
local wrapper = {
__index = function(_, k)
if mod[k] then
return function(...)
calls[k] = calls[k] or {}
table.insert(calls[k], {...})
return mod[k](...)
end
end
end,
}
return setmetatable({},wrapper), calls
end
then you use this function like so.
local M, calls = log(require("mod"))
M.foo('a', 1)
M.foo('b')
If your module is not just functions you would need to handle that in the wrapper, this wrapper assumes all indexes are a function.
after all your calls you can serialize the calls table to get the history of all the calls made. For the example code the table looks like
{
['foo'] = {{'a', 1}, {'b'}}
}

How do I get output for a XQuery in MarkLogic in a one line output?

Will elaborate - when I execute the following command :
let $value := xdmp:forest-status(
xdmp:forest-open-replica(
xdmp:database-forests(xdmp:database("Documents"))))
return $value
Above query returns a lot of information about the database "Documents" forest, like - forest-id, host-id, etc.
I only require that it should return only the "state" of my forest. How do I do that?
Use XPath to select what you want to return.
let $value := xdmp:forest-status(
xdmp:forest-open-replica(
xdmp:database-forests(xdmp:database("Documents"))))
return $value/*:state/text()
Also, no need for a FLWOR you could make it a one-liner:
xdmp:forest-status(
xdmp:forest-open-replica(
xdmp:database-forests(xdmp:database("Documents"))))/*:state/text()
Or you may find that using the arrow operator makes things easier to read instead of nested function calls and tons of parenthesis wrapping them:
(xdmp:database("Documents")
=> xdmp:database-forests()
=> xdmp:forest-open-replica()
=> xdmp:forest-status()
)/*:state/text()
The XML elements in the response are in the http://marklogic.com/xdmp/status/forest namespace. So, you would either need to declare the namespace (i.e. declare namespace f = "http://marklogic.com/xdmp/status/forest";) and use the prefix in your XPath (i.e. f:state), or just use the wildcard as I have done *:state

xquery matches - allow non existing nodes in loop

I have a for loop and want to filter some nodes, which works fine:
matches($doc/abc/#def, $filterA)
matches($doc/qwert/#xyz, $filterB)
What also works is, when $filterA, $filterB or both are empty, to return every node. What does not work however is to return the node if node abc or qwert do not exist. For the default value i currently use "" (empty string), is there another default value or another function I can use to make it work?
You can test whether the abc and qwert elements exist with the fn:exists() function. If you want it to pass if either of those elements do not exist, you can use fn:not() to negate a test for abc and qwert existence:
fn:not(fn:exists($doc/abc) and fn:exists($doc/qwert))
If you want a condition to pass if either $filterA or $filterB is empty:
fn:not(fn:exists($filterA) and fn:exists($filterB))
You can consolidate the matches() expressions a predicate to avoid repeating $doc (not a huge savings, but something to think of more generally when writing XPath expressions.
$doc[matches(abc/#def, $filterA) and matches(qwert/#xyz, $filterB)]
Putting it all together:
let $filterA := "a"
let $filterB :="b"
let $doc := <doc><abc def="a"/><qwert xyz="b"/></doc>
return
if (fn:not(fn:exists($doc/abc) and fn:exists($doc/qwert))
or fn:not(fn:exists($filterA) and fn:exists($filterB))
or $doc[matches(abc/#def, $filterA) and matches(qwert/#xyz, $filterB)])
then "pass - copy nodes"
else "fail"

Is it possible to combine if_not_exists and list_append in update_item

I'm trying to use the update_item functionality for DynamoDB in boto3.
I'm struggling right now to update lists for items. I would like to create a new list if the list does not exist yet and otherwise append to the existing list.
Using an UpdateExpression of the form SET my_list = list_append(my_list, :my_value) returns an error "The provided expression refers to an attribute that does not exist in the item" if the list does not exist yet.
Any idea how I would have to modify my UpdateExpression?
You can use list_append(if_not_exists()) construction.
UpdateExpression:
'SET my_list2 = list_append(if_not_exists(my_list2, :empty_list), :my_value)'
ExpressionAttributeValues:
{ ":my_value":{"L": [{"S":"test"}]}, ":empty_list":{"L":[]} }
Update: as mentioned in the comments, boto3 now raises an error for the expression above and a version without explicit types works: { ":my_value": ["test"], ":empty_list":[] }.
An alternative to Boris solution could be to use set instead of list datatype and use the ADD keyword, it does exactly what you want.
With Add, the update expression becomes: ADD setName :s
And the expression attribute values can be like: {":s": {"SS":["First", "Second"]}}
http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.ADD

Gremlin.compile() cannot execute query that works in gremlin console

When I execute the following in a gremlin console I get the expected result.
g.V('name', 'a').next().query().has('b', GREATER_THAN_EQUAL, 100).orderBy('timestamp', Order.DESC).edges()
Now I am trying to execute the same from Java (following this guide) however I cannot get it to work.
I've tried this
Pipe pipe = Gremlin.compile("_().query().has('b', GREATER_THAN_EQUAL, 100).orderBy('timestamp', Order.DESC).edges()");
pipe.setStarts(new SingleIterator<Vertex>(graph.getVertices("name", 'a').iterator().next()));
for(Object name : pipe) {
}
javax.script.ScriptException: javax.script.ScriptException:
groovy.lang.MissingMethodException: No signature of method:
com.tinkerpop.gremlin.groovy.GremlinGroovyPipeline.query() is
applicable for argument types: () values: [] Possible solutions:
every(), every(groovy.lang.Closure), grep(),
tree([Lcom.tinkerpop.pipes.PipeFunction;),
tree([Lgroovy.lang.Closure;),
tree(com.tinkerpop.pipes.util.structures.Tree)
And this
Pipe pipe = Gremlin.compile("_().next().query().has('b', GREATER_THAN_EQUAL, 100).orderBy('timestamp', Order.DESC).edges()");
pipe.setStarts(new SingleIterator<Vertex>(graph.getVertices("name", 'a').iterator().next()));
for(Object name : pipe) {
}
javax.script.ScriptException: javax.script.ScriptException:
groovy.lang.MissingMethodException: No signature of method:
com.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine.query()
is applicable for argument types: () values: [] Possible solutions:
every(), every(groovy.lang.Closure), grep(), grep(java.lang.Object),
any(), dump()
Any ideas?
This line looks suspicious to me:
Pipe pipe = Gremlin.compile("_().next().query().has('b', GREATER_THAN_EQUAL, 100).orderBy('timestamp', Order.DESC).edges()");
You are trying to compile a Pipe out of something that doesn't evaluate to a Pipeline. In other words, you start with the identity pipe (_()) but then you next() it out and drop down into a vertex query which returns edges() edges() returns a Iterator and not a Pipeline. If you look at the example of Gremlin.compile the evaluated code of the Gremlin string returns a pipeline.
Pipe pipe = Gremlin.compile("_().out('knows').name");
My guess is that if you instead changed your code to something like (untested):
Pipe pipe = Gremlin.compile("_().outE.has('b', GREATER_THAN_EQUAL, 100).order{it.b.timestamp <=> it.a.timestamp}");
pipe.setStarts(new SingleIterator<Vertex>(graph.getVertices("name", 'a').iterator().next()));
for(Object name : pipe) {
}
you might have some success. I suppose that if that worked, then you would want to figure out how to re-optimize your query as I guess that some backends could take optimize the orderBy of the Vertex query, whereas the order Gremlin step is just an in-memory sort.
Okay so I have decided to use GremlinGroovyScriptEngine instead of Gremlin.compile(). This approach is also described on the same guide and I actually prefer this because it gives me parameterisation and I don't need to modify the original query (replace g. with _()).
ScriptEngine engine = new GremlinGroovyScriptEngine();
Bindings bindings = engine.createBindings();
bindings.put("g", graph);
bindings.put("value", 100);
bindings.put("DESC", Order.DESC);
engine.eval("g.V('name', 'a').next().query().has('b', Compare.GREATER_THAN_EQUAL, value).orderBy('timestamp', DESC).edges()", bindings);
I would still be interested in knowing why Gremlin.compile did not work, hopefully the above will be helpful to someone else.

Resources