Skip to content

Conversation

@cyrusagent
Copy link

@cyrusagent cyrusagent bot commented Oct 20, 2025

Summary

Implements a complete SQLite persistence layer for the Logseq application following the design outlined in PER-12. This provides durable, local-first storage for Page aggregates and their associated Block hierarchies.

Changes Made

1. Database Schema (schema.rs)

  • 5 normalized tables with proper indexing and foreign key constraints:
    • pages: Page metadata (id, title, timestamps)
    • blocks: Block content with hierarchical parent_id references
    • block_children: Junction table for maintaining child order
    • urls: Extracted URLs from block content
    • page_references: Page references and tags
  • All tables use CASCADE delete for referential integrity
  • Idempotent initialization for safe repeated calls

2. Repository Implementation (sqlite_page_repository.rs)

  • SqlitePageRepository: Complete implementation of PageRepository trait
    • In-memory and file-based database support
    • Atomic transactions for all mutations
    • Two-pass block insertion to satisfy foreign key constraints:
      1. Insert all blocks (sorted by indent level)
      2. Insert block_children relationships
  • Full serialization/deserialization of complex Page aggregates
  • Proper error handling with conversion to DomainError

3. Dependencies

  • Added rusqlite v0.32 with bundled SQLite for portability

4. Testing

  • 11 comprehensive tests covering:
    • Schema initialization and idempotency
    • CRUD operations (save, find_by_id, find_by_title, find_all, delete)
    • Update/upsert functionality
    • Complex block hierarchies (3+ levels deep)
    • URL and page reference preservation
    • Edge cases (non-existent records)

Test Results

Summary: 172 tests run: 172 passed, 12 skipped

All persistence tests pass, including:

  • test_block_hierarchy_preserved
  • test_urls_and_references_preserved
  • test_save_and_find_by_id
  • test_update_page

Technical Highlights

  • Foreign key constraint handling: Blocks are sorted by indent level before insertion to ensure parents exist before children
  • Two-pass insertion strategy: Avoids FK violations in block_children table
  • Transaction safety: All write operations wrapped in transactions
  • Clean architecture: Follows existing patterns from QdrantVectorStore

Next Steps

  • Integration with application services (ImportService, SyncService)
  • Migration from in-memory to SQLite-backed repositories
  • Optional: Add full-text search with FTS5

🤖 Generated with Claude Code

This commit implements a complete SQLite persistence layer for the Logseq application,
providing durable storage for Page aggregates and their associated Block hierarchies.

## Changes

### Dependencies
- Added `rusqlite` 0.32 with bundled SQLite and JSON support to Cargo.toml

### Infrastructure Layer
- Created new `infrastructure/persistence` module with three components:
  - `schema.rs`: Database schema initialization and migrations
  - `sqlite_page_repository.rs`: SQLite implementation of PageRepository trait
  - `mod.rs`: Module exports

### Database Schema
Implements a normalized relational schema with five tables:
- `pages`: Stores page metadata (id, title, timestamps)
- `blocks`: Stores block content and hierarchy (with parent_id foreign key)
- `block_children`: Junction table maintaining child order
- `urls`: Stores URLs extracted from block content
- `page_references`: Stores page references and tags

All tables include appropriate indexes and foreign key constraints with CASCADE delete.

### Repository Implementation
- `SqlitePageRepository`: Full implementation of PageRepository trait
  - Supports in-memory and file-based databases
  - Atomic transactions for all write operations
  - Proper ordering of block insertion to satisfy foreign key constraints
  - Complete serialization/deserialization of Page aggregates including:
    - Hierarchical block structures
    - URLs and page references
    - Parent-child relationships

### Testing
- Comprehensive test suite with 11 tests covering:
  - Schema initialization and idempotency
  - CRUD operations (save, find, delete, update)
  - Complex block hierarchies
  - URL and page reference preservation
  - Edge cases (non-existent records, etc.)

All 172 tests pass successfully.

## Technical Notes
- Block insertion uses two-pass strategy: first insert all blocks, then insert
  child relationships to avoid foreign key constraint violations
- Blocks are sorted by indent level before insertion to ensure parents are
  created before children
- Uses rusqlite's bundled feature for portability

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants