Public
Edited
Sep 21, 2022
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// How many tasks are currently marked as completed?
// Store the result in a global variable to be able to access from an HTML cell.
numComplete = data.filter(d => d.is_complete).length
Insert cell
// How many tasks are currently marked as not-yet-completed?
// Store the result in a global variable to be able to access from an HTML cell.
numIncomplete = data.filter(d => !d.is_complete).length
Insert cell
// Use a mutable incrementing value to manually trigger Observable re-renders of downstream/dependent cells.
// Reference: https://observablehq.com/@observablehq/introduction-to-mutable-state
mutable i = 0
Insert cell
async function addTask(name) {
// Get the current datetime as an ISO string (which is the Timestamp format in DuckDB).
const dateString = (new Date()).toISOString();
// Execute a new database query containing an INSERT statement.
// Reference: https://duckdb.org/docs/sql/statements/insert
const result = await client1.query(`INSERT INTO todo VALUES (nextval('seq_task_id'), '${name}', '${dateString}', FALSE);`);
// Increment the counter to trigger a new SELECT query and subsequently a re-render of the todo list.
mutable i++;
return result;
}
Insert cell
async function updateTask(taskId, isComplete) {
// Execute a new database query containing an UPDATE statement.
// Reference: https://duckdb.org/docs/sql/statements/update
const result = await client1.query(
`UPDATE todo SET is_complete=${isComplete ? "TRUE" : "FALSE"} WHERE task_id=${taskId};`
);
// Increment the counter to trigger a new SELECT query and subsequently a re-render of the todo list.
mutable i++;
return result;
}
Insert cell
async function clearTasks(taskType) {
let result;
// The taskType parameter can either be null (all tasks), true (complete tasks), or false (incomplete tasks).
if(taskType === null) {
// Execute a new database query containing a DELETE statement (for all rows).
// Reference: https://duckdb.org/docs/sql/statements/delete
result = await client1.query(`DELETE FROM todo`);
} else {
// Execute a new database query containing a DELETE statement (for only those rows marked complete or not).
result = await client1.query(`DELETE FROM todo WHERE is_complete=${taskType ? "TRUE" : "FALSE"};`);
}
// Increment the counter to trigger a new SELECT query and subsequently a re-render of the todo list.
mutable i++;
return result;
}
Insert cell
data = {
// Force data to depend on i, to cause a new query to run upon increments of i.
console.log(i);
// Use a SELECT statement to get all rows from the database table called "todo".
// Convert the result to a plain array of JS objects.
return (await client1.query(`SELECT * FROM todo`)).toArray();
};
Insert cell
client1 = {
// Create a new DuckDB client to create/modify a DuckDB database.
const c = new DuckDBClient();

// Create a table called "todo" with four columns.
// Set task_id as the primary key.
await c.query(
`CREATE TABLE todo(task_id INTEGER PRIMARY KEY, name STRING, created TIMESTAMP, is_complete BOOLEAN)`
);
// Start a sequence to effectively set task_id to an "auto-increment"-ing value.
// Reference: https://stackoverflow.com/a/72883259
await c.query(`CREATE SEQUENCE seq_task_id START 1`);
// Insert values into "todo" to test.
/*await c.query(`INSERT INTO todo VALUES
(nextval('seq_task_id'), 'Walk dog', '1992-09-20 11:30:00', FALSE),
(nextval('seq_task_id'), 'Walk cat', '1992-09-20 12:30:00', TRUE);
`);*/
// Return the client object so that it is the value of the code cell.
return c;
}
Insert cell
<style>
/* Define styles using an HTML code cell and CSS inside of a <style/> element. */
.todo-header {
/* Create a blue dashed border. */
border-top: 3px dashed blue;
}
.todo-footer {
/* Create a blue dashed border. */
border-bottom: 3px dashed blue;
}
.todo {
/* Create a blue dashed border. */
border-left: 3px dashed blue;
border-right: 3px dashed blue;
/* Increase the padding and font size. */
padding: 10px;
font-size: 20px;
box-sizing: border-box;
margin: 0px;
}
.todo button {
/* Increase spacing between buttons. */
margin-right: 10px;
}
</style>
Insert cell
Insert cell
// Import the DuckDB client dependency for using an in-browser DuckDB database.
import {DuckDBClient} from '@cmudig/duckdb'
Insert cell
// Import the D3 dependency for using its convenient DOM element manipulation functions.
d3 = require("d3@6")
Insert cell
Insert cell
// Check the table schema.
client1.describe('todo')
Insert cell
client1
--- Check the table contents.
SELECT task_id, name FROM todo
Insert cell
client1
-- Check the table contents.
SUMMARIZE todo
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more