CRDT Maps
A map is a kind of appendable collection that stores key-value pairs. A collection of elements can be accessed using keys of type string.
Creation
How to create a map and write to the map:
aqua-- Creationmap: %u64-- Append different key-value pairsmap <<- "key", 1234map <<- "key", foo()map <<- "second key", foo()
aqua-- Creationmap: %u64-- Append different key-value pairsmap <<- "key", 1234map <<- "key", foo()map <<- "second key", foo()
Maps can contain only immutable data types elements. Arrows, streams, other maps, closures and abilities are not allowed in the type declarations.
Access
Access to keys and elements can create different behaviours based on tasks.
Get array of elements by a key
Get array of all elements by key:
aquavalues = map.get("key")
aquavalues = map.get("key")
Get stream of elements by a key
Get stream of elements by key, later you can join on the stream to wait for specific number of elements in it:
aquavaluesStream <- map.getStream("key")-- wait for 9 elementsjoin valuesStream[9]
aquavaluesStream <- map.getStream("key")-- wait for 9 elementsjoin valuesStream[9]
Get array of keys
Get array of all keys (of type []string) in map:
aquakeys <- map.keys()
aquakeys <- map.keys()
Get stream of keys
Get stream of keys (of type *string):
aquakeysStream <- map.keysStream()
aquakeysStream <- map.keysStream()
Check if a key is presented
Check if key contains at least one element, return boolean:
aquakeyExist <- map.contains("key")
aquakeyExist <- map.contains("key")
Difference between methods
get, keys and contains methods return immutable result in-place, on the other hand getStream and keysStream methods return streams which will eventually contain updates of the map. For example:
aquamap: %stringfor p <- peers par:on p:-- add element to map on different peersmap <<- "exec", p-- in this case there is no way to predict what number of elements will be in `results`results = map.get("exec")resultsStream = map.getStream("exec")-- here we can wait for any number of results depends on logic of a program-- let's wait a respond from 5 peersjoin resultsStream[4]-- after join we can be sure that in `resultsStream` will be 5 or more elementsfuncThatNeeds5Responses(resultsStream)
aquamap: %stringfor p <- peers par:on p:-- add element to map on different peersmap <<- "exec", p-- in this case there is no way to predict what number of elements will be in `results`results = map.get("exec")resultsStream = map.getStream("exec")-- here we can wait for any number of results depends on logic of a program-- let's wait a respond from 5 peersjoin resultsStream[4]-- after join we can be sure that in `resultsStream` will be 5 or more elementsfuncThatNeeds5Responses(resultsStream)
To dive deeper read about join behavior and streams.
Iteration
Maps can be used in for operations in two ways:
aquamap: %u64-- key is a string and value is u64for key, value <- map:foo(key, value)for kv <- map:foo(kv.key, kv.value)
aquamap: %u64-- key is a string and value is u64for key, value <- map:foo(key, value)for kv <- map:foo(kv.key, kv.value)
for will iterate over key-value pairs by unique keys. Last write win resolution is applied to the values. Order of iteration generally is the same as the order of insertion. Example:
aquamap: %stringmap <<- "a", "a1"map <<- "b", "b1"map <<- "b", "b2"map <<- "c", "c1"map <<- "c", "c2"map <<- "c", "c3"result: *stringfor k, v <- map:result <<- v
aquamap: %stringmap <<- "a", "a1"map <<- "b", "b1"map <<- "b", "b2"map <<- "c", "c1"map <<- "c", "c2"map <<- "c", "c3"result: *stringfor k, v <- map:result <<- v
in the end, result will be ["a1", "b2", "c3"].