WOQL RDF List Operations
RDF Lists (rdf:List) are linked list data structures in RDF that use rdf:first, rdf:rest, and rdf:nil predicates. TerminusDB provides a comprehensive WOQL library for manipulating these structures efficiently.
What You'll Learn
By the end of this guide, you'll understand:
- How RDF lists are structured internally
- How to create, read, and modify RDF lists using WOQL
- Best practices for list operations in TerminusDB
Understanding RDF List Structure
An RDF list is a chain of "cons cells" where each cell contains:
rdf:first→ the value at this positionrdf:rest→ pointer to the next cell (orrdf:nilfor the end)
List: ["First", "Second", "Third"]
Structure:
Cell1 → rdf:type = rdf:List
→ rdf:first = "First"
→ rdf:rest = Cell2
Cell2 → rdf:type = rdf:List
→ rdf:first = "Second"
→ rdf:rest = Cell3
Cell3 → rdf:type = rdf:List
→ rdf:first = "Third"
→ rdf:rest = rdf:nilOperations Overview
| Category | Operations | Description |
|---|---|---|
| Creation | rdflist_empty, rdflist_is_empty | Create and check empty lists |
| Access | rdflist_peek, rdflist_member, rdflist_length, rdflist_list, rdflist_slice | Read list elements |
| Modification | rdflist_push, rdflist_pop, rdflist_append, rdflist_insert, rdflist_drop, rdflist_clear | Add, remove, and modify elements |
| Transformation | rdflist_swap, rdflist_reverse | Reorder list elements |
Quick Start Example
Here's a complete example demonstrating common list operations:
import { WOQLClient, WOQL } from "@terminusdb/terminusdb-client";
const client = new WOQLClient("http://localhost:6363", {
user: "admin",
organization: "admin",
key: "root"
});
// Create a list manually, independent of documents
const createList = WOQL.and(
WOQL.idgen_random("terminusdb://data/Cons/", "v:cell1"),
WOQL.idgen_random("terminusdb://data/Cons/", "v:cell2"),
WOQL.idgen_random("terminusdb://data/Cons/", "v:cell3"),
WOQL.add_triple("v:cell1", "rdf:type", "rdf:List"),
WOQL.add_triple("v:cell1", "rdf:first", WOQL.string("Task A")),
WOQL.add_triple("v:cell1", "rdf:rest", "v:cell2"),
WOQL.add_triple("v:cell2", "rdf:type", "rdf:List"),
WOQL.add_triple("v:cell2", "rdf:first", WOQL.string("Task B")),
WOQL.add_triple("v:cell2", "rdf:rest", "v:cell3"),
WOQL.add_triple("v:cell3", "rdf:type", "rdf:List"),
WOQL.add_triple("v:cell3", "rdf:first", WOQL.string("Task C")),
WOQL.add_triple("v:cell3", "rdf:rest", "rdf:nil")
);
const result = await client.query(createList);
const listHead = result.bindings[0]["cell1"];
// Read all values
const readAll = WOQL.lib().rdflist_member(listHead, "v:value");
const values = await client.query(readAll);
// Returns: ["Task A", "Task B", "Task C"]
// Get list length
const getLength = WOQL.lib().rdflist_length(listHead, "v:count");
const lengthResult = await client.query(getLength);
// Returns: 3Detailed Guides
Explore each category of operations in detail:
List Creation
Learn how to create empty lists and check if lists are empty.
List Access
Learn how to read elements from lists using peek, member, length, list, and slice operations.
List Modification
Learn how to add, remove, and modify list elements with push, pop, append, insert, drop, and clear.
List Transformation
Learn how to reorder lists with swap and reverse operations.
Performance Characteristics
| Operation | Time Complexity | Description |
|---|---|---|
rdflist_peek | O(1) | Direct access to first element |
rdflist_push | O(1) | Add to front (in-place modification) |
rdflist_pop | O(1) | Remove from front (in-place modification) |
rdflist_member | O(n) | Single traversal |
rdflist_length | O(n) | Single traversal with count |
rdflist_append | O(n) | Must traverse to find end |
rdflist_insert | O(n) | Traverse to position |
rdflist_drop | O(n) | Traverse to position |
rdflist_clear | O(n) | Delete all cells |
rdflist_reverse | O(n) | In-place reversal |
rdflist_swap | O(n) | Traverse to both positions |
Best Practices
Use Library Functions
Prefer library functions over manual triple manipulation:
// Good - use library functions to ensure accurate operations
WOQL.lib().rdflist_push(listHead, WOQL.string("New Item"))
// Avoid manual manipulation as ensuring accuracy is hard
WOQL.and(
WOQL.idgen_random(...),
WOQL.add_triple(...),
// ... many lines
)Descriptive Variable Names
Use descriptive variable names with the v: prefix, or use the WOQL.vars() function:
// Good
WOQL.lib().rdflist_member("List/tasks", "v:task_title")
// Less clear
WOQL.lib().rdflist_member("List/tasks", "v:x")Error Handling
Always check results for empty bindings:
const result = await client.query(query);
if (!result?.bindings || result.bindings.length === 0) {
// Handle empty result
}Atomic Operations
Group related list operations in a single query for atomicity for ACID transactions:
// Atomic operation - both succeed or both fail
WOQL.and(
WOQL.lib().rdflist_pop("List/queue", "v:item"),
WOQL.lib().rdflist_append("List/processed", "v:item", "v:new_cell")
)Working with Document References
Lists can contain references to documents:
// Schema with list of document references
const schema = {
"@type": "Class",
"@id": "Playlist",
"@key": { "@type": "Random" },
name: "xsd:string",
songs: { "@type": "List", "@class": "Song" }
};
// Read songs with their details
const songsQuery = WOQL.and(
WOQL.lib().rdflist_member(playlistHead, "v:song_id"),
WOQL.triple("v:song_id", "title", "v:title"),
WOQL.triple("v:song_id", "artist", "v:artist")
);Read More
- Integration Tests - Complete test examples
- RDF List Vocabulary - W3C RDF Schema specification
- WOQL Basics - WOQL fundamentals
- Query Arrays and Sets - Working with other collection types
- Path Queries - Advanced traversal patterns