Skip to main content

cognee_lib/api/notebooks/
mod.rs

1//! `cognee_lib::notebooks` — per-user notebook CRUD facade.
2//!
3//! Wraps `cognee_database::NotebookDb` with tutorial seeding and the Python
4//! truthiness-bug compat notes documented in `docs/http-server/routers/notebooks.md`.
5
6pub mod tutorial;
7
8use std::sync::Arc;
9
10use thiserror::Error;
11use uuid::Uuid;
12
13use cognee_database::{
14    DatabaseError, Notebook, NotebookDb, NotebookUpdatePatch, seed_tutorials_if_first_call,
15};
16
17pub use tutorial::{TUTORIAL_BASICS_ID, TUTORIAL_PYTHON_DEV_ID};
18
19// ─── NotebookError ────────────────────────────────────────────────────────────
20
21#[derive(Debug, Error)]
22pub enum NotebookError {
23    #[error("database error: {0}")]
24    Database(#[from] DatabaseError),
25}
26
27// ─── Public API ───────────────────────────────────────────────────────────────
28
29/// List all notebooks for `user_id`.
30///
31/// On the very first call for a new user this seeds the two bundled tutorial
32/// notebooks (idempotent — re-running is safe).
33pub async fn list_notebooks(
34    db: &Arc<dyn NotebookDb>,
35    user_id: Uuid,
36) -> Result<Vec<Notebook>, NotebookError> {
37    seed_tutorials_if_first_call(db.as_ref(), user_id).await?;
38    Ok(db.list_by_owner(user_id).await?)
39}
40
41/// Create a new notebook.
42///
43/// `deletable` is always forced to `true` regardless of the parameter value —
44/// this replicates Python's `deletable=deletable or True` truthiness bug so
45/// the HTTP surface is byte-identical to the Python SDK.
46pub async fn create_notebook(
47    db: &Arc<dyn NotebookDb>,
48    user_id: Uuid,
49    name: String,
50    cells: serde_json::Value,
51    _deletable: bool,
52) -> Result<Notebook, NotebookError> {
53    // Python's create_notebook always ends up with deletable=True due to the
54    // `deletable or True` expression.  We replicate the bug for wire compat.
55    Ok(db.create(user_id, name, cells, true).await?)
56}
57
58/// Update a notebook's name and/or cells.
59///
60/// Replicates Python's truthiness-gated assignment:
61/// - `name` is only updated when `patch.name` is `Some` and non-empty.
62/// - `cells` is only updated when `patch.cells` is `Some(Value::Array(v))` with
63///   `v` non-empty — an empty cells list **does not clear cells**.
64pub async fn update_notebook(
65    db: &Arc<dyn NotebookDb>,
66    id: Uuid,
67    user_id: Uuid,
68    patch: NotebookUpdatePatch,
69) -> Result<Option<Notebook>, NotebookError> {
70    Ok(db.update(id, user_id, patch).await?)
71}
72
73/// Delete a notebook.  Returns `true` if a row was removed.
74pub async fn delete_notebook(
75    db: &Arc<dyn NotebookDb>,
76    id: Uuid,
77    user_id: Uuid,
78) -> Result<bool, NotebookError> {
79    Ok(db.delete(id, user_id).await?)
80}