Collections
Adama has three primary collection types: list<T>, map<K,V>, and arrays (T[]). This is where you'll spend a lot of your time when working with data.
List Methods
Lists are dynamic, ordered collections. You typically get them from table queries via iterate.
size()
Returns how many elements are in the list.
record Record {
public int id;
}
table<Record> _records;
public formula record_count = (iterate _records).size();
list<int> numbers;
int count = numbers.size();
| Parameter | Type | Description |
|---|---|---|
| (none) | - | - |
Returns: int - The number of elements
toArray()
Converts the list to a fixed-size array.
procedure foo() {
list<int> numbers;
int[] arr = numbers.toArray();
}
| Parameter | Type | Description |
|---|---|---|
| (none) | - | - |
Returns: T[] - An array containing all list elements
reverse()
Gives you a new list with the elements in reverse order.
procedure foo() {
list<int> numbers;
list<int> reversed = numbers.reverse(); // [3, 2, 1]
}
| Parameter | Type | Description |
|---|---|---|
| (none) | - | - |
Returns: list<T> - A new list with reversed order
skip(n)
Returns a new list with the first n elements removed. Good for pagination.
procedure foo() {
list<int> numbers;
list<int> skipped = numbers.skip(2); // [3, 4, 5]
}
| Parameter | Type | Description |
|---|---|---|
| n | int |
Number of elements to skip |
Returns: list<T> - A new list without the first n elements
drop(n)
Returns a new list with the last n elements removed.
procedure foo() {
list<int> numbers;
list<int> dropped = numbers.drop(2); // [1, 2, 3]
}
| Parameter | Type | Description |
|---|---|---|
| n | int |
Number of elements to remove from end |
Returns: list<T> - A new list without the last n elements
flatten()
Takes a nested list structure and flattens it into a single list.
procedure foo() {
list<list<int>> nested;
list<int> flat = nested.flatten(); // [1, 2, 3, 4]
}
| Parameter | Type | Description |
|---|---|---|
| (none) | - | - |
Returns: list<U> - A flattened list where U is the inner list type
manifest()
Extracts values from a list<maybe<T>>, keeping only the ones that actually have values. The name is a bit unusual (I know), but it "manifests" the present values out of the maybe wrappers.
procedure foo() {
list<maybe<int>> maybes;
list<int> values = maybes.manifest(); // [1, 3]
}
| Parameter | Type | Description |
|---|---|---|
| (none) | - | - |
Returns: list<U> - A list of the non-empty values
Index Access
Lists support index access with brackets. It returns maybe<T> since the index might be out of bounds -- no exceptions, just an empty maybe.
procedure foo() {
list<int> numbers;
maybe<int> first = numbers[0];
maybe<int> tenth = numbers[9]; // Empty if list has fewer than 10 elements
if (first as value) {
// Use value safely
}
}
Map Methods
Maps are key-value dictionaries. Keys must be types that work as map domains: int, long, string, principal.
size()
Returns the number of entries.
map<string, int> scores;
int count = scores.size();
| Parameter | Type | Description |
|---|---|---|
| (none) | - | - |
Returns: int - The number of key-value pairs
has(key)
Checks if a key exists.
map<string, int> scores;
bool hasAlice = scores.has("Alice");
| Parameter | Type | Description |
|---|---|---|
| key | K |
The key to check for |
Returns: bool - True if the key exists
insert(map)
Merges another map into this one.
procedure foo() {
map<string, int> scores1;
map<string, int> scores2;
map<string, int> combined = scores1.insert(scores2);
}
| Parameter | Type | Description |
|---|---|---|
| map | map<K,V> |
The map to merge |
Returns: map<K,V> - The merged map
remove(key)
Removes an entry and returns the value that was there (if any).
procedure foo() {
map<string, int> scores;
maybe<int> removed = scores.remove("Alice");
}
| Parameter | Type | Description |
|---|---|---|
| key | K |
The key to remove |
Returns: maybe<V> - The removed value, or empty if key didn't exist
clear()
Removes everything.
procedure foo() {
map<string, int> scores;
scores.clear();
}
| Parameter | Type | Description |
|---|---|---|
| (none) | - | - |
Returns: void
min()
Returns the entry with the smallest key.
procedure foo() {
map<int, string> lookup;
maybe<pair<int, string>> minimum = lookup.min();
}
| Parameter | Type | Description |
|---|---|---|
| (none) | - | - |
Returns: maybe<pair<K,V>> - The entry with the smallest key, or empty if map is empty
max()
Returns the entry with the largest key.
procedure foo() {
map<int, string> lookup;
maybe<pair<int, string>> maximum = lookup.max();
}
| Parameter | Type | Description |
|---|---|---|
| (none) | - | - |
Returns: maybe<pair<K,V>> - The entry with the largest key, or empty if map is empty
Key Access
Maps support bracket notation for key-based access. Returns maybe<V> because the key might not be there.
procedure foo() {
map<string, int> scores;
maybe<int> aliceScore = scores["Alice"];
if (aliceScore as score) {
// Use score safely
}
}
Key Mutation
You can also mutate maps directly through bracket notation:
map<int, int> notifications;
int thread_id = 1;
procedure foo() {
// Set a value
notifications[thread_id] = 5;
// Increment a value
notifications[thread_id]++;
// Remove a key
notifications.remove(thread_id);
// Clear all entries
notifications.clear();
}
Iterating Maps
Use foreach to walk over map entries:
map<string, int> scores;
procedure foo() {
foreach (kvp in scores) {
string name = kvp.key;
int score = kvp.value;
// Process each entry
}
}
Array Methods
Arrays are fixed-size. You create them from literals or by converting lists.
size()
Returns the number of elements.
procedure foo() {
int[] numbers = [1, 2, 3, 4, 5];
int length = numbers.size(); // 5
}
| Parameter | Type | Description |
|---|---|---|
| (none) | - | - |
Returns: int - The number of elements
Index Access
Arrays support direct index access.
procedure foo() {
int[] numbers = [1, 2, 3];
maybe<int> first = numbers[0]; // 1
maybe<int> second = numbers[1]; // 2
}
Working with Tables and Iterate
The most common way to get lists in Adama is through iterate on tables. This creates reactive lists that update automatically when the underlying data changes.
Basic Iteration
record Player {
public int id;
public string name;
public int score;
}
table<Player> _players;
// Basic list from table
public formula all_players = iterate _players;
// With filtering
public formula high_scorers = iterate _players where score > 100;
// With ordering
public formula leaderboard = iterate _players order by score desc;
// With limit
public formula top_three = iterate _players order by score desc limit 3;
Combining Operations
record Player {
public int id;
public string name;
public int score;
public bool active;
}
table<Player> _players;
// Skip and limit for pagination
public formula page_two = iterate _players
order by name asc
offset 10
limit 10;
// Filter, order, and limit
public formula best_active = iterate _players
where active == true
order by score desc
limit 5;
Bulk Operations
Lists from iterate support bulk assignment and method execution. This is one of my favorite features -- you can mutate entire result sets in one shot:
record Player {
public int id;
public int score;
public bool active;
method double_score() {
score = score * 2;
}
}
table<Player> _players;
// Bulk field assignment
procedure reset_scores() {
(iterate _players).score = 0;
}
// Bulk method execution
procedure double_all() {
(iterate _players).double_score();
}
// Bulk deletion
procedure remove_inactive() {
(iterate _players where active == false).delete();
}
Reduce Operations
The reduce keyword groups list items by a field and applies a function to each group. It's basically GROUP BY from SQL.
record Sale {
public int id;
public string category;
public double amount;
}
table<Sale> _sales;
// Group sales by category
public formula sales_by_category =
iterate _sales
reduce on category via (@lambda items: items);
// Count sales per category
public formula category_counts =
iterate _sales
reduce on category via (@lambda items: items.size());
Method Summary Tables
List Methods
| Method | Description | Returns |
|---|---|---|
size() |
Number of elements | int |
toArray() |
Convert to array | T[] |
reverse() |
Reverse order | list<T> |
skip(n) |
Skip first n elements | list<T> |
drop(n) |
Remove last n elements | list<T> |
flatten() |
Flatten nested lists | list<U> |
manifest() |
Extract maybe values | list<U> |
[index] |
Access by index | maybe<T> |
Map Methods
| Method | Description | Returns |
|---|---|---|
size() |
Number of entries | int |
has(key) |
Check if key exists | bool |
insert(map) |
Merge maps | map<K,V> |
remove(key) |
Remove entry | maybe<V> |
clear() |
Remove all entries | void |
min() |
Entry with minimum key | maybe<pair<K,V>> |
max() |
Entry with maximum key | maybe<pair<K,V>> |
[key] |
Access by key | maybe<V> |
Array Methods
| Method | Description | Returns |
|---|---|---|
size() |
Number of elements | int |
[index] |
Access by index | maybe<T> |
Common Patterns
Pagination
record Item {
public int id;
public datetime created;
}
table<Item> _items;
view int page;
int page_size = 10;
bubble paginated_items = iterate _items
order by created desc
offset (@viewer.page * page_size)
limit page_size;
Finding Elements
record User {
public int id;
public string role;
}
table<User> _users;
// Find first match
public formula first_admin =
(iterate _users where role == "admin" limit 1)[0];
// Check if any match exists
public formula has_admin =
(iterate _users where role == "admin" limit 1).size() > 0;
Transforming Lists
record Player {
public int id;
public string name;
}
table<Player> _players;
// Use formulas to transform list data
public formula player_names =
iterate _players order by name asc;
// Client can extract just the names from the list