revelation-songbook

Crates.iorevelation-songbook
lib.rsrevelation-songbook
version0.1.1
created_at2025-12-26 10:53:17.430777+00
updated_at2026-01-04 04:34:11.85036+00
descriptionSongbook domain with ChordPro parser for Revelation project
homepage
repositoryhttps://github.com/Revelation-Path/revelation-songbook
max_upload_size
id2005564
size180,003
RA (RAprogramm)

documentation

README

revelation-songbook

Crates.io Documentation License: MIT REUSE Coverage

Songbook domain types with ChordPro parser for Rust applications.

Table of Contents

Overview

revelation-songbook provides a complete solution for managing worship songs and hymnals in Rust applications. It includes:

  • Domain types for songs, songbooks, playlists, and user interactions
  • ChordPro parser for parsing and rendering chord charts
  • Chord transposition with support for sharps and flats
  • Port traits for database and search operations
⬆ back to top

Features

  • ChordPro Format Support: Full parsing of ChordPro directives and inline chords
  • Chord Transposition: Transpose songs up/down with sharp or flat notation
  • Song Management: Songs, songbooks, editions with full metadata
  • Playlist Support: User playlists with ordering
  • Search: Full-text search with highlighting
  • History & Favorites: Track user interactions
  • Categories & Tags: Flexible song organization
  • Multi-language: Support for alternate titles and translations
⬆ back to top

Installation

Add to your Cargo.toml:

[dependencies]
revelation-songbook = "0.1"

With specific features:

[dependencies]
revelation-songbook = { version = "0.1", features = ["db", "api", "backend"] }
⬆ back to top

Architecture

┌─────────────────────────────────────────────────────────────┐
│                      Your Application                       │
├─────────────────────────────────────────────────────────────┤
│                   revelation-songbook                       │
│  ┌─────────────────────┐    ┌─────────────────────────────┐ │
│  │    Domain Types     │    │       Port Traits           │ │
│  │  ─────────────────  │    │  ─────────────────────────  │ │
│  │  Song, Songbook     │    │  SongRead, SongWrite        │ │
│  │  Playlist, Edition  │◄───│  SongbookRead, Search       │ │
│  │  Chord, Note        │    │  Favorites, History         │ │
│  │  ParsedSong         │    │  Playlist, Tags             │ │
│  └─────────────────────┘    └─────────────────────────────┘ │
│  ┌─────────────────────────────────────────────────────────┐│
│  │                   ChordPro Parser                       ││
│  │  Parse → Sections → Lines → Chords → Transpose          ││
│  └─────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘
⬆ back to top

Domain Types

Core Types

Type Description
Song Full song with metadata, content, categories, tags
SongSummary Lightweight song for lists
Songbook Collection of songs (hymnal, songbook)
SongbookEdition Specific edition of a songbook
Playlist User-created song collection
PlaylistItem Song in a playlist with ordering

Music Types

Type Description
Chord Parsed chord with root, quality, bass note
PositionedChord Chord with position in text
Note Musical note (A-G with sharps/flats)
ParsedSong Structured song from ChordPro parsing
SongSection Verse, chorus, bridge, etc.
SongLine Line of text with positioned chords

Organization

Type Description
SongCategory Enum: Worship, Hymn, Christmas, Easter, etc.
SongTag User-defined tags
SongFilters Filter criteria for song queries
SongHistory User view history entry
⬆ back to top

ChordPro Parser

Parse ChordPro format into structured data:

use revelation_songbook::ChordProParser;

let content = r#"
{title: Amazing Grace}
{artist: John Newton}
{key: G}
{tempo: 80}

{start_of_verse: Verse 1}
[G]Amazing [G7]grace, how [C]sweet the [G]sound
That [G]saved a [Em]wretch like [D]me
{end_of_verse}

{start_of_chorus}
[G]I once was [G7]lost, but [C]now am [G]found
Was [G]blind, but [D]now I [G]see
{end_of_chorus}
"#;

let song = ChordProParser::parse(content);

assert_eq!(song.title, Some("Amazing Grace".into()));
assert_eq!(song.key, Some("G".into()));
assert_eq!(song.sections.len(), 2);

Supported Directives

Directive Description
{title: ...} Song title
{subtitle: ...} Subtitle
{artist: ...} Artist/composer
{key: ...} Original key
{tempo: ...} BPM
{capo: ...} Capo position
{start_of_verse} Begin verse section
{start_of_chorus} Begin chorus section
{start_of_bridge} Begin bridge section
{end_of_*} End section
⬆ back to top

Chord Transposition

Transpose chords with proper enharmonic handling:

use revelation_songbook::Chord;

let chord = Chord::parse("Am7").unwrap();

// Transpose up 2 semitones (use sharps)
let up = chord.transpose(2, false);
assert_eq!(up.to_string(), "Bm7");

// Transpose down 1 semitone (use flats)
let down = chord.transpose(-1, true);
assert_eq!(down.to_string(), "Abm7");

// Chord with bass note
let slash = Chord::parse("G/B").unwrap();
let transposed = slash.transpose(2, false);
assert_eq!(transposed.to_string(), "A/C#");
⬆ back to top

Port Traits

Port traits define interfaces for data access. Implement these in your adapters:

SongRead

Read operations for songs:

pub trait SongRead: Send + Sync {
    fn get_song(&self, id: Uuid) -> impl Future<Output = AppResult<Option<Song>>> + Send;
    fn get_songs(&self, filters: &SongFilters) -> impl Future<Output = AppResult<Vec<SongSummary>>> + Send;
    fn get_songs_by_songbook(&self, songbook_id: Uuid) -> impl Future<Output = AppResult<Vec<SongSummary>>> + Send;
}

SongWrite

Write operations for songs:

pub trait SongWrite: Send + Sync {
    fn create_song(&self, song: CreateSong) -> impl Future<Output = AppResult<Song>> + Send;
    fn update_song(&self, id: Uuid, song: UpdateSong) -> impl Future<Output = AppResult<Song>> + Send;
    fn delete_song(&self, id: Uuid) -> impl Future<Output = AppResult<()>> + Send;
}

SongSearch

Full-text search:

pub trait SongSearch: Send + Sync {
    fn search(&self, query: &str, limit: i64) -> impl Future<Output = AppResult<Vec<SearchResult>>> + Send;
}
⬆ back to top

Usage Examples

Basic Song Creation

use revelation_songbook::{Song, SongCategory, CreateSong};
use uuid::Uuid;

let create = CreateSong {
    songbook_id: None,
    number: Some(1),
    title: "Amazing Grace".into(),
    title_alt: None,
    author_lyrics: Some("John Newton".into()),
    author_music: None,
    translator: None,
    year_written: Some(1779),
    copyright: None,
    original_key: Some("G".into()),
    tempo: Some(80),
    time_signature: Some("4/4".into()),
    content: "{title: Amazing Grace}\n[G]Amazing grace...".into(),
    categories: vec![SongCategory::Hymn],
    tag_ids: vec![],
    source_url: None,
};

Working with Playlists

use revelation_songbook::{Playlist, PlaylistItem};

let playlist = Playlist {
    id: Uuid::new_v4(),
    user_id: user_id,
    name: "Sunday Service".into(),
    description: Some("Songs for this week".into()),
    is_public: false,
    songs_count: 5,
};
⬆ back to top

Feature Flags

Feature Default Description
db No Adds sqlx::Type derives for PostgreSQL enum mapping
api No Adds utoipa::ToSchema derives for OpenAPI documentation
backend No Enables port traits (requires masterror for error handling)

Feature Combinations

# Frontend/WASM - minimal, just types and parser
revelation-songbook = "0.1"

# Backend with PostgreSQL
revelation-songbook = { version = "0.1", features = ["db", "backend"] }

# Full backend with OpenAPI docs
revelation-songbook = { version = "0.1", features = ["db", "api", "backend"] }
⬆ back to top

Code Coverage

We maintain high test coverage to ensure reliability:

Sunburst

The inner circle represents the entire project. Moving outward: folders, then individual files.

Coverage Sunburst

Grid

Each block represents a file. Size = number of statements, color = coverage level.

Coverage Grid

Icicle

Hierarchical view from project to individual files.

Coverage Icicle

⬆ back to top

Dependencies

Crate Purpose
serde Serialization/deserialization
uuid Unique identifiers
chrono Date/time handling
validator Input validation
regex ChordPro parsing
sqlx Database type derives (optional)
utoipa OpenAPI schemas (optional)
masterror Error handling for ports (optional)
⬆ back to top

Related Crates

⬆ back to top

License

This project is licensed under the MIT License (SPDX: MIT).

All files include SPDX license identifiers for REUSE compliance.


Part of the Revelation Project - Building tools for Bible study and worship.

⬆ back to top
Commit count: 0

cargo fmt