Skip to content

Instantly share code, notes, and snippets.

@grtjn
Created November 6, 2017 19:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save grtjn/f24a747b823fc3f28e806d911242eb88 to your computer and use it in GitHub Desktop.
Save grtjn/f24a747b823fc3f28e806d911242eb88 to your computer and use it in GitHub Desktop.
Saint Nicolas Lottery
xquery version "1.0-ml";
declare function local:draw-one($remaining-map, $member) {
let $household-name := name($member/..)
let $household-map := map:get($remaining-map, $household-name)
let $household-count := count(map:keys($household-map))
let $household-key := $household-name || "/" || head(map:keys($household-map))
let $remaining-members :=
for $h-name in map:keys($remaining-map)
for $m-name in map:keys(map:get($remaining-map, $h-name))
return $h-name || "/" || $m-name
let $household-position :=
for $key at $x in $remaining-members
where $key eq $household-key
return $x
let $remaining-count := count($remaining-members) - $household-count
let $random := xdmp:random($remaining-count - 1) + 1
let $target-key :=
if ($random lt $household-position) then
for $m at $x in $remaining-members
where $x eq $random
return $m
else
for $m at $x in $remaining-members
where $x eq ($random + $household-count)
return $m
let $target-household-name := substring-before($target-key, "/")
let $target-member-name := substring-after($target-key, "/")
let $_ := map:delete(map:get($remaining-map, $target-household-name), $target-member-name)
return $target-key
};
declare function local:draw-all($family) {
try {
let $members := $family//text()
let $remaining-map := xdmp:from-json($family)
let $result := map:map()
let $_ :=
for $member in $members
let $member-key := name($member/..) || "/" || name($member)
let $target-key := local:draw-one($remaining-map, $member)
return
if ($target-key eq $member-key) then
error(xs:QName("FAIL"), $member-key || " picked him/herself!")
else if (substring-before($target-key, "/") eq substring-before($member-key, "/")) then
error(xs:QName("FAIL"), $member-key || " picked " || $target-key || "!")
else
map:put($result, $member-key, $target-key)
return $result
} catch ($ignore) {
local:draw-all($family)
}
};
declare function local:send-mail(
$recipient-name as xs:string,
$recipient-email as xs:string,
$subject as xs:string,
$message as item()
) as empty-sequence() {
xdmp:email(
<em:Message
xmlns:em="URN:ietf:params:email-xml:"
xmlns:rf="URN:ietf:params:rfc822:">
<rf:subject>{$subject}</rf:subject>
<rf:from>
<em:Address>
<em:name>Saint Nicolas Lottery</em:name>
<em:adrs>saint-nicolas-lottery@example.com</em:adrs>
</em:Address>
</rf:from>
<rf:to>
<em:Address>
<em:name>{$recipient-name}</em:name>
<em:adrs>{$recipient-email}</em:adrs>
</em:Address>
</rf:to>
<em:content>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>{$subject}</title>
</head>
<body>{$message}</body>
</html>
</em:content>
</em:Message>
)
};
let $family := xdmp:unquote('
{
Household1: {
Grandpa: "grandpa@family.com",
Grandma: "grandma@family.com"
},
Household2: {
Son1: "son1@family.com",
Wife1: "wife1@family.com",
Grandchild1: "grandchild1@family.com"
},
Household3: {
Daughter2: "daughter2@family.com",
Husband2: "husband2@family.com",
Grandchild2: "grandchild2@family.com",
Grandchild3: "grandchild3@family.com"
}
}
')
let $result := local:draw-all($family)
let $_ := xdmp:save("/tmp/drawing.json", xdmp:to-json($result))
for $draw in map:keys($result)
let $household-name := substring-before($draw, "/")
let $member-name := substring-after($draw, "/")
let $member-email := map:get(map:get(xdmp:from-json($family), $household-name), $member-name)
let $target-name := substring-after(map:get($result, $draw), "/")
return local:send-mail(
$member-name,
$member-email,
"Saint Nicolas lottery for 5 December",
"Dear " || $member-name || ", you have drawn " || $target-name || "."
)
@grtjn
Copy link
Author

grtjn commented Nov 7, 2017

Input is a JSON family tree, output as email. Runs on MarkLogic. Note that it draws names from other households only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment