I'm setting up unit testing using marklogic-unit-test and one thing I'd like to do is check a given document has a particular permission. However, when I test my permission against a Sequence of permissions, I get an XDMP-NONMIXEDCOMPLEXCONT error. I assume this has to do with the fact that permissions are complex objects and not something like a simple string, because this works with collections.
const test = require("/test/test-helper.xqy");
let p1 = Sequence.from([xdmp.permission("rest-reader", "read", "element")]);
let p2 = Sequence.from([
xdmp.permission("rest-reader", "read", "element"),
xdmp.permission("rest-writer", "update", "element")
]);
test.assertAtLeastOneEqual(p1, p2)
Which returns:
[javascript] XDMP-NONMIXEDCOMPLEXCONT: fn:data(<sec:permission
xmlns:sec="http://marklogic.com/xdmp/security">
<sec:capability>...</sec:capability>...</sec:permission>)
-- Node has complex type with non-mixed complex content
The best alternative I can come up with is to explicitly loop over the Sequence and do the comparison with fn.deepEqual on each element. Is there a better way?
The test.assertAtLeastOneEqual() function expects atomic values (item() signature). The only test helper function that can handle elements is test.assertEqualXml(), but that looks for exact matches. I think your best bet is to stringify the permissions. Something like this:
const test = require("/test/test-helper.xqy");
let p1 = [xdmp.permission("rest-reader", "read")];
let p2 = [
xdmp.permission("rest-reader", "read"),
xdmp.permission("rest-writer", "update")
];
p1 = Sequence.from(p1.map(p => xdmp.roleName(p.roleId) + ':' + p.capability));
p2 = Sequence.from(p2.map(p => xdmp.roleName(p.roleId) + ':' + p.capability));
test.assertAtLeastOneEqual(p1, p2)
Related
In F#, assume I have a person record as:
type person =
{ LastName: string option
BirthDate: System.DateTime option }
Now, I want to create a list of 100 persons (this fails. Both name and The System.DateTime(...) is incorrect):
let people = [for a in 1 .. 100
do yield {
LastName= Some "LastName"+a
BirthDate = System.DateTime(2012,11,27)
}]
How is this done?
TIA
There are two separate issues with the code, but your general approach is good!
First, Some "LastName"+a is interpereted as (Some "LastName")+a, which is not the right parenthesization. Also a is an int which cannot be automatically turned into a string, so you need to explicitly convert it. The correct version is Some("LastName" + string a).
Second, System.DateTime(2012,11,27) is DateTime, but you need an option. You can fix this just by adding Some and the right parentheses, i.e. Some(System.DateTime(2012,11,27)).
As a bonus, you can reduce do yield to -> (this is just a syntactic sugar to make this kind of thing shorter). I would write:
open System
let people =
[ for a in 1 .. 100 ->
{ LastName= Some ("LastName"+string a)
BirthDate = Some(DateTime(2012,11,27)) } ]
Let's say I have a giant table, something like:
test.test[1].testing.test.test_test
The table isn't guaranteed to exist. Neither are the tables containing it. I would like to just be able to do:
if test.test[1].testing.test.test_test then
print("it exits!")
end
But of course, this would give me an "Attempt to index ? (a nil value)" error if any of the indices aren't yet defined. So many times, I'll end up doing something like this:
if test then
if test.test then
if test.test[1] then
if test.test[1].testing then -- and so on
Is there a better, less-tedious way to accomplish this?
You can write a function that takes a list of keys to look up and does whatever action you want if it finds the entry. Here's an example:
function forindices(f, table, indices)
local entry = table
for _,idx in ipairs(indices) do
if type(entry) == 'table' and entry[idx] then
entry = entry[idx]
else
entry = nil
break
end
end
if entry then
f()
end
end
test = {test = {{testing = {test = {test_test = 5}}}}}
-- prints "it exists"
forindices(function () print("it exists") end,
test,
{"test", 1, "testing", "test", "test_test"})
-- doesn't print
forindices(function () print("it exists") end,
test,
{"test", 1, "nope", "test", "test_test"})
As an aside, the functional programming concept that solves this kind of problem is the Maybe monad. You could probably solve this with a Lua implementation of monads, though it wouldn't be very nice since there's no syntactic sugar for it.
You can avoid raising errors by setting an __index metamethod for nil:
debug.setmetatable(nil, { __index=function () end })
print(test.test[1].testing.test.test_test)
test = {test = {{testing = {test = {test_test = 5}}}}}
print(test.test[1].testing.test.test_test)
You also use an empty table:
debug.setmetatable(nil, { __index={} })
I have 2 immutable case classes A(source, key, value) and B(source, key, value)
I want to add A over B in such a way when 'source' and 'key' doesn't exist, to be added from A to the B and when 'source' and 'key' exist to replace the value from B with the one from A. The same way 'merge_array' function from php works on a multidimensional array.
I tried with 'A.union(B).groupBy(.key)' and then 'groupBy(.source)' and get the 1st value. But then I realized that I can never be sure that first value will always be the value of A.
I'm quite new to scala and I really ran out of ideas how I could do this from a functional immutable point of view.
Anyone has any idea how I could do this?
Thank you
Edit:
case class TranslationValue(source: String, key: String, value: String)
def main(args:Array[String]):Unit = {
println(merge(data1.toSet, data2.toSet))
}
def merge(a: Set[TranslationValue], b: Set[TranslationValue]) = {
a.union(b).groupBy(_.key).flatMap{ case (s, v) =>
v.groupBy(_.source).flatMap{case (s1, v1) => {
for (res <- 0 to 0) yield v1.head
}
}
}
}
Example
data1 has this data
Set(
TranslationValue(messages,No,No),
TranslationValue(messages,OrdRef,Order Reference),
TranslationValue(messages,OrdId,Order Id)
)
data2 has this data
Set(
TranslationValue(messages,No,No),
TranslationValue(messages,OrdRef,OrderRef)
TranslationValue(messages,Name,Name)
)
putting data1 over data2 I want to obtain
List(
TranslationValue(messages,No,No),
TranslationValue(messages,OrdRef,Order Reference),
TranslationValue(messages,OrdId,Order Id)
TranslationValue(messages,Name,Name)
)
I know that what I do can be done better, but like I said, I'm learning :)
you can group in one go:
def merge(a: Seq[TranslationValue], b: Seq[TranslationValue]) = {
a.union(b).groupBy(t=>(t.key,t.source)).map(c=>c._2.head)
}
i think you could also override the equals method for TranslationValue so that two translation values are equal when source and key are the same(the hashcode method has also to be overridden). Then a.union(b) would be enough.
edit:
It seems Set doesnt guarantee order of items(Scala: Can I rely on the order of items in a Set?), but a seq should.
I have a sorting problem in Scala that I could certainly solve with brute-force, but I'm hopeful there is a more clever/elegant solution available. Suppose I have a list of strings in no particular order:
val keys = List("john", "jill", "ganesh", "wei", "bruce", "123", "Pantera")
Then at random, I receive the values for these keys at random (full-disclosure, I'm experiencing this problem in an akka actor, so events are not in order):
def receive:Receive = {
case Value(key, otherStuff) => // key is an element in keys ...
And I want to store these results in a List where the Value objects appear in the same order as their key fields in the keys list. For instance, I may have this list after receiving the first two Value messages:
List(Value("ganesh", stuff1), Value("bruce", stuff2))
ganesh appears before bruce merely because he appears earlier in the keys list. Once the third message is received, I should insert it into this list in the correct location per the ordering established by keys. For instance, on receiving wei I should insert him into the middle:
List(Value("ganesh", stuff1), Value("wei", stuff3), Value("bruce", stuff2))
At any point during this process, my list may be incomplete but in the expected order. Since the keys are redundant with my Value data, I throw them away once the list of values is complete.
Show me what you've got!
I assume you want no worse than O(n log n) performance. So:
val order = keys.zipWithIndex.toMap
var part = collection.immutable.TreeSet.empty[Value](
math.Ordering.by(v => order(v.key))
)
Then you just add your items.
scala> part = part + Value("ganesh", 0.1)
part: scala.collection.immutable.TreeSet[Value] =
TreeSet(Value(ganesh,0.1))
scala> part = part + Value("bruce", 0.2)
part: scala.collection.immutable.TreeSet[Value] =
TreeSet(Value(ganesh,0.1), Value(bruce,0.2))
scala> part = part + Value("wei", 0.3)
part: scala.collection.immutable.TreeSet[Value] =
TreeSet(Value(ganesh,0.1), Value(wei,0.3), Value(bruce,0.2))
When you're done, you can .toList it. While you're building it, you probably don't want to, since updating a list in random order so that it is in a desired sorted order is an obligatory O(n^2) cost.
Edit: with your example of seven items, my solution takes about 1/3 the time of Jean-Philippe's. For 25 items, it's 1/10th the time. 1/30th for 200 (which is the difference between 6 ms and 0.2 ms on my machine).
If you can use a ListMap instead of a list of tuples to store values while they're gathered, this could work. ListMap preserves insertion order.
class MyActor(keys: List[String]) extends Actor {
def initial(values: ListMap[String, Option[Value]]): Receive = {
case v # Value(key, otherStuff) =>
if(values.forall(_._2.isDefined))
context.become(valuesReceived(values.updated(key, Some(v)).collect { case (_, Some(v)) => v))
else
context.become(initial(keys, values.updated(key, Some(v))))
}
def valuesReceived(values: Seq[Value]): Receive = { } // whatever you need
def receive = initial(keys.map { k => (k -> None) })
}
(warning: not compiled)
For example i have erlang record:
-record(state, {clients
}).
Can i make from clients field list?
That I could keep in client filed as in normal list? And how can i add some values in this list?
Thank you.
Maybe you mean something like:
-module(reclist).
-export([empty_state/0, some_state/0,
add_client/1, del_client/1,
get_clients/1]).
-record(state,
{
clients = [] ::[pos_integer()],
dbname ::char()
}).
empty_state() ->
#state{}.
some_state() ->
#state{
clients = [1,2,3],
dbname = "QA"}.
del_client(Client) ->
S = some_state(),
C = S#state.clients,
S#state{clients = lists:delete(Client, C)}.
add_client(Client) ->
S = some_state(),
C = S#state.clients,
S#state{clients = [Client|C]}.
get_clients(#state{clients = C, dbname = _D}) ->
C.
Test:
1> reclist:empty_state().
{state,[],undefined}
2> reclist:some_state().
{state,[1,2,3],"QA"}
3> reclist:add_client(4).
{state,[4,1,2,3],"QA"}
4> reclist:del_client(2).
{state,[1,3],"QA"}
::[pos_integer()] means that the type of the field is a list of positive integer values, starting from 1; it's the hint for the analysis tool dialyzer, when it performs type checking.
Erlang also allows you use pattern matching on records:
5> reclist:get_clients(reclist:some_state()).
[1,2,3]
Further reading:
Records
Types and Function Specifications
dialyzer(1)
#JUST MY correct OPINION's answer made me remember that I love how Haskell goes about getting the values of the fields in the data type.
Here's a definition of a data type, stolen from Learn You a Haskell for Great Good!, which leverages record syntax:
data Car = Car {company :: String
,model :: String
,year :: Int
} deriving (Show)
It creates functions company, model and year, that lookup fields in the data type. We first make a new car:
ghci> Car "Toyota" "Supra" 2005
Car {company = "Toyota", model = "Supra", year = 2005}
Or, using record syntax (the order of fields doesn't matter):
ghci> Car {model = "Supra", year = 2005, company = "Toyota"}
Car {company = "Toyota", model = "Supra", year = 2005}
ghci> let supra = Car {model = "Supra", year = 2005, company = "Toyota"}
ghci> year supra
2005
We can even use pattern matching:
ghci> let (Car {company = c, model = m, year = y}) = supra
ghci> "This " ++ c ++ " " ++ m ++ " was made in " ++ show y
"This Toyota Supra was made in 2005"
I remember there were attempts to implement something similar to Haskell's record syntax in Erlang, but not sure if they were successful.
Some posts, concerning these attempts:
In Response to "What Sucks About Erlang"
Geeking out with Lisp Flavoured Erlang. However I would ignore parameterized modules here.
It seems that LFE uses macros, which are similar to what provides Scheme (Racket, for instance), when you want to create a new value of some structure:
> (define-struct car (company model year))
> (define supra (make-car "Toyota" "Supra" 2005))
> (car-model supra)
"Supra"
I hope we'll have something close to Haskell record syntax in the future, that would be really practically useful and handy.
Yasir's answer is the correct one, but I'm going to show you WHY it works the way it works so you can understand records a bit better.
Records in Erlang are a hack (and a pretty ugly one). Using the record definition from Yasir's answer...
-record(state,
{
clients = [] ::[pos_integer()],
dbname ::char()
}).
...when you instantiate this with #state{} (as Yasir did in empty_state/0 function), what you really get back is this:
{state, [], undefined}
That is to say your "record" is just a tuple tagged with the name of the record (state in this case) followed by the record's contents. Inside BEAM itself there is no record. It's just another tuple with Erlang data types contained within it. This is the key to understanding how things work (and the limitations of records to boot).
Now when Yasir did this...
add_client(Client) ->
S = some_state(),
C = S#state.clients,
S#state{clients = [Client|C]}.
...the S#state.clients bit translates into code internally that looks like element(2,S). You're using, in other words, standard tuple manipulation functions. S#state.clients is just a symbolic way of saying the same thing, but in a way that lets you know what element 2 actually is. It's syntactic saccharine that's an improvement over keeping track of individual fields in your tuples in an error-prone way.
Now for that last S#state{clients = [Client|C]} bit, I'm not absolutely positive as to what code is generated behind the scenes, but it is likely just straightforward stuff that does the equivalent of {state, [Client|C], element(3,S)}. It:
tags a new tuple with the name of the record (provided as #state),
copies the elements from S (dictated by the S# portion),
except for the clients piece overridden by {clients = [Client|C]}.
All of this magic is done via a preprocessing hack behind the scenes.
Understanding how records work behind the scenes is beneficial both for understanding code written using records as well as for understanding how to use them yourself (not to mention understanding why things that seem to "make sense" don't work with records -- because they don't actually exist down in the abstract machine...yet).
If you are only adding or removing single items from the clients list in the state you could cut down on typing with a macro.
-record(state, {clients = [] }).
-define(AddClientToState(Client,State),
State#state{clients = lists:append([Client], State#state.clients) } ).
-define(RemoveClientFromState(Client,State),
State#state{clients = lists:delete(Client, State#state.clients) } ).
Here is a test escript that demonstrates:
#!/usr/bin/env escript
-record(state, {clients = [] }).
-define(AddClientToState(Client,State),
State#state{clients = lists:append([Client], State#state.clients)} ).
-define(RemoveClientFromState(Client,State),
State#state{clients = lists:delete(Client, State#state.clients)} ).
main(_) ->
%Start with a state with a empty list of clients.
State0 = #state{},
io:format("Empty State: ~p~n",[State0]),
%Add foo to the list
State1 = ?AddClientToState(foo,State0),
io:format("State after adding foo: ~p~n",[State1]),
%Add bar to the list.
State2 = ?AddClientToState(bar,State1),
io:format("State after adding bar: ~p~n",[State2]),
%Add baz to the list.
State3 = ?AddClientToState(baz,State2),
io:format("State after adding baz: ~p~n",[State3]),
%Remove bar from the list.
State4 = ?RemoveClientFromState(bar,State3),
io:format("State after removing bar: ~p~n",[State4]).
Result:
Empty State: {state,[]}
State after adding foo: {state,[foo]}
State after adding bar: {state,[bar,foo]}
State after adding baz: {state,[baz,bar,foo]}
State after removing bar: {state,[baz,foo]}