This guide covers operations for modifying RDF lists. These operations allow you to add, remove, and manage list elements.
Use the operators together for various scenarios. To operate a list like a stack, use the push and pop operators. To create a queue, use the append and pop operator (append to the end of the list is O(n) in performance and pop is o(1)).
What You'll Learn
- How to add elements to the front or back of a list
- How to remove elements from a list
- How to insert elements at specific positions
- How to clear an entire list
Operations Summary
| Operation | Description | Time Complexity |
|---|---|---|
rdflist_push | Add element to front (in-place) | O(1) |
rdflist_pop | Remove element from front (in-place) | O(1) |
rdflist_append | Add element to end | O(n) |
rdflist_insert | Insert at specific position | O(n) |
rdflist_drop | Remove element at position | O(n) |
rdflist_clear | Remove all elements | O(n) |
rdflist_push
Adds a new element to the front of a list. This is an in-place operation that modifies the list structure at the same head IRI. Useful for creating stacks or queues.
Syntax
WOQL.lib().rdflist_push(consSubject, value)Parameters
| Parameter | Type | Description |
|---|---|---|
consSubject | string | The list head identifier |
value | any | Value to add (use WOQL.string() for strings) |
Example
// Before: [A, B, C]
const pushQuery = WOQL.lib().rdflist_push(listHead, WOQL.string("Z"));
const result = await client.query(pushQuery);
// After: [Z, A, B, C]
// Verify the change
const peekQuery = WOQL.lib().rdflist_peek(listHead, "v:first");
const peekResult = await client.query(peekQuery);
console.log(peekResult.bindings[0]["first"]["@value"]); // "Z"Building Lists with Multiple Pushes
// Create a list by pushing elements (results in reverse order)
const createQuery = WOQL.and(
WOQL.idgen_random("terminusdb://data/Cons/", "v:list"),
WOQL.add_triple("v:list", "rdf:type", "rdf:List"),
WOQL.add_triple("v:list", "rdf:first", WOQL.string("First")),
WOQL.add_triple("v:list", "rdf:rest", "rdf:nil")
);
const result = await client.query(createQuery);
const listHead = result.bindings[0]["list"];
// Push more elements
await client.query(WOQL.lib().rdflist_push(listHead, WOQL.string("Second")));
await client.query(WOQL.lib().rdflist_push(listHead, WOQL.string("Third")));
// List is now: [Third, Second, First]Use Cases
- Stack operations: Implement LIFO (Last In, First Out) structures
- Prepending: Add items to the beginning efficiently
- Building lists: Create lists by pushing elements
rdflist_pop
Removes and returns the first element from a list. This is an in-place operation, which means that the list (the Cons) reference from where it is referenced stays the same, such as from a document.
Syntax
WOQL.lib().rdflist_pop(consSubject, valueVar)Parameters
| Parameter | Type | Description |
|---|---|---|
consSubject | string | The list head identifier |
valueVar | string | Variable to bind the removed value |
Example
// Before: [X, Y, Z]
const popQuery = WOQL.lib().rdflist_pop(listHead, "v:popped");
const result = await client.query(popQuery);
// After: [Y, Z]
const popped = result.bindings[0]["popped"]["@value"];
console.log(`Removed: ${popped}`); // "X"
// Verify the list changed
const lengthQuery = WOQL.lib().rdflist_length(listHead, "v:len");
const lengthResult = await client.query(lengthQuery);
console.log(`Length: ${lengthResult.bindings[0]["len"]["@value"]}`); // "2"Use Cases
- Stack operations: Implement pop for LIFO structures
- Queue processing: Remove items from front
- Destructuring: Extract head and work with tail
rdflist_append
Adds an element to the end of a list. Creates a new cons cell and links it to the end of the list. Useful for appending elements to a FIFO queue.
Syntax
WOQL.lib().rdflist_append(consSubject, value, newCellVar)Parameters
| Parameter | Type | Description |
|---|---|---|
consSubject | string | The list head identifier |
value | any | Value to append |
newCellVar | string | Variable to bind the new cell ID |
Example
// Before: [A, B, C]
const appendQuery = WOQL.lib().rdflist_append(
listHead,
WOQL.string("D"),
"v:new_cell"
);
const result = await client.query(appendQuery);
// After: [A, B, C, D]
// The operation deletes the old nil reference and creates a new cell
console.log(`Inserts: ${result.inserts}`);
console.log(`Deletes: ${result.deletes}`);Use Cases
- Queue operations: Add items to the back (FIFO)
- Building ordered lists: Maintain insertion order
- Extending lists: Add items without changing existing order
rdflist_insert
Inserts an element at a specific position in the list. Uses 0-based indexing.
Syntax
WOQL.lib().rdflist_insert(consSubject, position, value)Parameters
| Parameter | Type | Description |
|---|---|---|
consSubject | string | The list head identifier |
position | number | Index where to insert (0-based) |
value | any | Value to insert |
Examples
// List: [A, B, C]
// Insert at position 0 (head): [X, A, B, C]
await client.query(
WOQL.lib().rdflist_insert(listHead, 0, WOQL.string("X"))
);
// Insert at position 1 (after head): [A, Y, B, C]
await client.query(
WOQL.lib().rdflist_insert(listHead, 1, WOQL.string("Y"))
);
// Insert at position 2 (middle): [A, B, Z, C]
await client.query(
WOQL.lib().rdflist_insert(listHead, 2, WOQL.string("Z"))
);Verification Example
// Create list: [A, B, C]
const createQuery = 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("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("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("C")),
WOQL.add_triple("v:cell3", "rdf:rest", "rdf:nil")
);
const result = await client.query(createQuery);
const listHead = result.bindings[0]["cell1"];
// Insert "X" at position 0
await client.query(
WOQL.lib().rdflist_insert(listHead, 0, WOQL.string("X"))
);
// Verify: should be [X, A, B, C]
const readQuery = WOQL.lib().rdflist_member(listHead, "v:val");
const readResult = await client.query(readQuery);
const values = readResult.bindings.map(b => b["val"]["@value"]);
console.log(values); // ["X", "A", "B", "C"]rdflist_drop
Removes an element at a specific position from the list. Uses 0-based indexing. Remember to also delete subdocuments using delete_document() if needed by using rdflist_slice() to query them.
Syntax
WOQL.lib().rdflist_drop(consSubject, position)Parameters
| Parameter | Type | Description |
|---|---|---|
consSubject | string | The list head identifier |
position | number | Index of element to remove (0-based) |
Examples
// List: [A, B, C]
// Drop at position 0 (head): [B, C]
await client.query(WOQL.lib().rdflist_drop(listHead, 0));
// Drop at position 1 (middle): [A, C]
await client.query(WOQL.lib().rdflist_drop(listHead, 1));
// Drop at position 2 (last): [A, B]
await client.query(WOQL.lib().rdflist_drop(listHead, 2));Use Cases
- Removal by index: Delete specific items
- Filtering: Remove unwanted elements
- Trimming: Remove elements from specific positions
rdflist_clear
Removes all elements from a list, deleting all cons cells and returning rdf:nil.
Syntax
WOQL.lib().rdflist_clear(consSubject, emptyListVar)Parameters
| Parameter | Type | Description |
|---|---|---|
consSubject | string | The list head identifier |
emptyListVar | string | Variable to bind the empty list (rdf:nil) |
Example
// Clear a list
const clearQuery = WOQL.lib().rdflist_clear(listHead, "v:empty");
const result = await client.query(clearQuery);
const emptyList = result.bindings[0]["empty"];
console.log(emptyList); // "rdf:nil"
console.log(`Deleted ${result.deletes} triples`);
// Verify the old cons cells are gone
const verifyQuery = WOQL.triple(listHead, "v:pred", "v:obj");
const verifyResult = await client.query(verifyQuery);
console.log(verifyResult.bindings.length); // 0Important: Document References
When clearing a list that contains document references, only the list structure is deleted, not the referenced documents:
// Create tasks
await client.addDocument([
{ "@type": "Task", "@id": "Task/1", title: "Task 1" },
{ "@type": "Task", "@id": "Task/2", title: "Task 2" }
]);
// Build list of task references
// ... (list contains Task/1 and Task/2)
// Clear the list
await client.query(WOQL.lib().rdflist_clear(listHead, "v:empty"));
// Tasks still exist!
const task1 = await client.getDocument({ id: "Task/1" });
console.log(task1.title); // "Task 1" - still therePattern: Delete All Referenced Documents and Clear List
const deleteAndClear = WOQL.and(
// Get the list head
WOQL.triple("Project/1", "tasks", "v:listHead"),
// Delete all documents in the list
WOQL.group_by(
[],
"v:task",
"v:tasks",
WOQL.and(
WOQL.lib().rdflist_member("v:listHead", "v:task"),
WOQL.delete_document("v:task")
)
),
// Clear the list structure
WOQL.lib().rdflist_clear("v:listHead", "v:empty"),
// Update the parent reference to point to empty list
WOQL.delete_triple("Project/1", "tasks", "v:listHead"),
WOQL.add_triple("Project/1", "tasks", "v:empty")
);
await client.query(deleteAndClear);Complete Example: Task Queue
import { WOQLClient, WOQL } from "@terminusdb/terminusdb-client";
async function taskQueueDemo(client) {
// Create initial queue with one task
const createQueue = WOQL.and(
WOQL.idgen_random("terminusdb://data/Cons/", "v:queue"),
WOQL.add_triple("v:queue", "rdf:type", "rdf:List"),
WOQL.add_triple("v:queue", "rdf:first", WOQL.string("Initial Task")),
WOQL.add_triple("v:queue", "rdf:rest", "rdf:nil")
);
const result = await client.query(createQueue);
const queue = result.bindings[0]["queue"];
// Add tasks to the back (queue behavior)
await client.query(
WOQL.lib().rdflist_append(queue, WOQL.string("Task 2"), "v:cell")
);
await client.query(
WOQL.lib().rdflist_append(queue, WOQL.string("Task 3"), "v:cell")
);
console.log("Queue after appends:");
const allTasks = await client.query(
WOQL.lib().rdflist_list(queue, "v:tasks")
);
console.log(allTasks.bindings[0]["tasks"].map(t => t["@value"]));
// ["Initial Task", "Task 2", "Task 3"]
// Process (pop) from the front
const popResult = await client.query(
WOQL.lib().rdflist_pop(queue, "v:task")
);
console.log(`Processing: ${popResult.bindings[0]["task"]["@value"]}`);
// "Initial Task"
// Insert high-priority task at position 0
await client.query(
WOQL.lib().rdflist_insert(queue, 0, WOQL.string("URGENT"))
);
console.log("Queue after urgent insert:");
const finalTasks = await client.query(
WOQL.lib().rdflist_list(queue, "v:tasks")
);
console.log(finalTasks.bindings[0]["tasks"].map(t => t["@value"]));
// ["URGENT", "Task 2", "Task 3"]
// Clear the queue when done
await client.query(WOQL.lib().rdflist_clear(queue, "v:empty"));
console.log("Queue cleared");
}Read More
- RDF List Operations Overview - Main guide
- List Creation Operations - Creating lists
- List Access Operations - Reading list elements
- List Transformation Operations - Reordering lists
- Integration Tests - Complete test examples