Current section

Files

Jump to
scriptorium src scriptorium models database.gleam
Raw

src/scriptorium/models/database.gleam

//// The database contains all the parsed data from the input files, but not
//// processed content.
import gleam/dict.{type Dict}
import gleam/list
import gleam/option.{None, Some}
import gleam/order.{type Order}
import scriptorium/models/menu.{type MenuItem}
import scriptorium/models/page.{type Page}
import scriptorium/models/post.{type Post, type Tag}
import scriptorium/utils/date.{type Month}
import scriptorium/utils/ordered_tree.{type OrderedTree}
import scriptorium/utils/uniqid.{type Generator, type UniqID}
/// Internal post ID, generated automatically.
pub type PostID =
UniqID
pub type PostWithID {
PostWithID(id: PostID, post: Post)
}
/// All tags and their posts.
pub type TagPosts =
Dict(Tag, OrderedTree(PostWithID))
/// Posts organised by month. This is used inside `YearPosts`.
pub type MonthPosts =
Dict(Month, OrderedTree(PostWithID))
/// Posts organised by year, containing posts organised by month.
pub type YearPosts =
Dict(Int, MonthPosts)
pub opaque type Database {
Database(
posts: OrderedTree(PostWithID),
pages: List(Page),
menu: List(MenuItem),
tags: TagPosts,
years: YearPosts,
posts_by_id: Dict(PostID, Post),
id_generator: Generator,
)
}
/// Create a new empty database.
pub fn new() -> Database {
Database(
posts: new_tree(),
pages: [],
menu: [],
tags: dict.new(),
years: dict.new(),
posts_by_id: dict.new(),
id_generator: uniqid.new(),
)
}
/// Add a post into the database.
pub fn add_post(db: Database, post: Post) -> Database {
let post_date = post.get_date(post)
let #(id, id_generator) = uniqid.get(db.id_generator)
let post_with_id = PostWithID(id, post)
let posts_by_id = dict.insert(db.posts_by_id, id, post)
let posts = ordered_tree.insert(db.posts, post_with_id)
let tags =
list.fold(post.tags, db.tags, fn(acc, tag) {
dict.update(acc, tag, fn(existing) {
case existing {
None ->
new_tree()
|> ordered_tree.insert(post_with_id)
Some(posts) -> ordered_tree.insert(posts, post_with_id)
}
})
})
let years =
dict.update(db.years, post_date.year, fn(years) {
case years {
None ->
dict.from_list([
#(
post_date.month,
new_tree()
|> ordered_tree.insert(post_with_id),
),
])
Some(months) ->
dict.update(months, post_date.month, fn(posts) {
case posts {
None ->
new_tree()
|> ordered_tree.insert(post_with_id)
Some(posts) -> ordered_tree.insert(posts, post_with_id)
}
})
}
})
Database(
..db,
id_generator: id_generator,
posts: posts,
tags: tags,
years: years,
posts_by_id: posts_by_id,
)
}
/// Add a page into the database.
pub fn add_page(db: Database, page: Page) -> Database {
Database(..db, pages: [page, ..db.pages])
}
/// Set the menu items of the database, replacing any old ones.
pub fn set_menu(db: Database, menu: List(MenuItem)) -> Database {
Database(..db, menu: menu)
}
/// Get posts organised by tags.
pub fn tags(db: Database) {
db.tags
}
/// Get posts organised by years and months.
pub fn years(db: Database) {
db.years
}
/// Get all posts in the given order.
pub fn get_posts_with_ids(
db: Database,
order: ordered_tree.WalkOrder,
) -> List(PostWithID) {
ordered_tree.to_list(db.posts, order)
}
/// Get pages.
pub fn pages(db: Database) {
db.pages
}
/// Get menu items.
pub fn menu(db: Database) {
db.menu
}
fn new_tree() -> OrderedTree(PostWithID) {
ordered_tree.new(comparator)
}
fn comparator(a: PostWithID, b: PostWithID) -> Order {
post.comparator(a.post, b.post)
}