website/lib/DB.rakumod

128 lines
3.7 KiB
Raku
Raw Normal View History

2025-01-21 03:24:01 -05:00
use v6.e.PREVIEW;
2025-01-21 01:31:33 -05:00
#| Post database
unit module DB;
use Pandoc;
2025-01-21 03:24:01 -05:00
use JSON::Class:auth<zef:vrurg>;
2025-01-21 01:31:33 -05:00
2025-01-22 20:13:45 -05:00
use DB::Post;
use DB::BlogMeta;
2025-01-22 20:49:27 -05:00
use DB::MarkdownPost;
2025-01-22 20:53:52 -05:00
use DB::IdrisPost;
use DB::PlaceholderPost;
2025-02-03 21:36:07 -05:00
use Config;
2025-01-22 05:00:58 -05:00
subset PostTypes where MarkdownPost:D | IdrisPost:D | PlaceholderPost:D;
2025-01-21 03:24:01 -05:00
#| The top level posts database
class PostDB {
#| The metadata for the blog
2025-01-21 22:08:10 -05:00
has BlogMeta:D $.meta is required;
#| A mapping from post ids to posts
# has %.posts is Posts;
has %.posts{Int} of PostTypes = %();
#| The post id to use for placeholder posts
has Int $.placeholder-id = 0;
2025-01-22 05:00:58 -05:00
2025-01-22 04:29:44 -05:00
#| Get the next unused post ID
method next-post-id(--> Int) {
2025-01-22 05:00:58 -05:00
if %!posts.elems > 0 {
2025-01-22 04:29:44 -05:00
%!posts.keys.max + 1
} else {
0
}
}
#| Insert a new post to the DB, returning its id
2025-01-22 05:00:58 -05:00
method insert-post(PostTypes $post --> Int) {
2025-01-22 04:29:44 -05:00
my $id = self.next-post-id;
%!posts{$id} = $post;
$id
}
#| Initialize a new database
method init(BlogMeta:D $meta --> PostDB:D) {
my %posts{Int} of PostTypes = %();
%posts{0} = PlaceholderPost.empty;
PostDB.new(
meta => $meta,
posts => %posts,
)
}
#| Write a database to a directory
method write(IO::Path:D $dir) {
my $posts-dir = $dir.add('posts/');
# Make sure directory structrue exists
mkdir $dir unless $dir.e;
mkdir $posts-dir unless $posts-dir.e;
# Write out metadata
# TODO: Track changes and only write changed files
$dir.add('meta.json').spurt: $!meta.to-json;
# Write out posts (ids are the filename)
for %!posts.kv -> $key, $value {
$posts-dir.add("$key.json").spurt: $value.to-json;
}
}
2025-02-03 21:36:07 -05:00
#| Render the site to the provided output directory
method render(IO::Path:D $out-dir, Config:D :$config = Config.new) {
my $posts = $out-dir.add('posts/');
my $by-id = $posts.add('by-id/');
my $by-slug = $posts.add('by-slug/');
# Make sure the directory structure exists
mkdir $out-dir unless $out-dir.e;
mkdir $posts unless $posts.e;
mkdir $by-id unless $by-id.e;
mkdir $by-slug unless $by-slug.e;
# Render all the posts and make symlinks
for %!posts.kv -> $id, $post {
my $html =
$config.generate-post:
$post.title, $post.render-html, $!meta;
my $id-path = $by-id.add: "$id.html";
$id-path.spurt: $html;
for $post.all-slugs -> $slug {
$by-slug.add($slug).symlink: $id-path;
}
}
# Render the archive
# Render the rss/atom feed
# Render the index
die "Not Implemented"
}
}
2025-02-03 21:36:07 -05:00
#| Read the database out of a directory
sub read-db(IO::Path:D $dir --> PostDB:D) is export {
my $posts-dir = $dir.add('posts/');
die "DB directory does not exist" unless $dir.e;
die "posts directory does not exist" unless $posts-dir.e;
# Read metadata
my $meta = BlogMeta.from-json: $dir.add('meta.json').slurp;
# Read posts
my %posts{Int} of PostTypes = %();
for dir $posts-dir -> $post {
my $id = $post.extension("").basename.Int;
# TODO: Dejankify this, maybe see if we can work with parsed, but
# unmarshalled json
given $post.slurp {
when /'"placeholder": true'/ {
%posts{$id} = PlaceholderPost.from-json: $_;
}
when /'"markdown": true'/ {
%posts{$id} = MarkdownPost.from-json: $_;
}
when /'"idris": true'/ {
%posts{$id} = IdrisPost.from-json: $_;
}
default {
die "Unsupported post type: $post";
}
}
}
# Build db structure
PostDB.new: meta => $meta, posts => %posts
2025-01-21 03:24:01 -05:00
}