diff --git a/blog b/blog index b6b183d..81c14b0 100755 --- a/blog +++ b/blog @@ -21,17 +21,23 @@ sub load-db(IO::Path $file --> DB::PostDB:D) { } } +#| Write the databse to the provided file +sub write-db(IO::Path $file, DB::PostDB $db) { + my $output = $db.to-json; + $file.spurt: $output; +} + #| Initalize the database multi MAIN( "db", "init", #| The path of the database file - IO::Path :$file = $blog-dir.add("db.json"), + IO::Path(Str) :$db-file = $blog-dir.add("db.json"), #| Overwrite an already existing database file Bool :$force ) { - die "Database file already exists, use --force to overwrite: {$file.Str}" - if $file.e && !$force; + die "Database file already exists, use --force to overwrite: {$db-file.Str}" + if $db-file.e && !$force; print "Blog Title: "; my $title = get; @@ -43,9 +49,9 @@ multi MAIN( my $db = DB::PostDB.new: meta => $meta; if $force { - $file.spurt: $db.to-json, :create-only; + $db-file.spurt: $db.to-json, :create-only; } else { - $file.spurt: $db.to-json; + $db-file.spurt: $db.to-json; } } @@ -54,8 +60,34 @@ multi MAIN( "db", "verify", #| The path of the database file - IO::Path :$file = $blog-dir.add("db.json"), + IO::Path(Str) :$db = $blog-dir.add("db.json"), ) { - load-db $file; + load-db $db; say "Database OK"; } + +#| Create a new markdown post + +multi MAIN( + "new", + "markdown", + #| The path to the markdown file + IO::Path(Str) $source, + #| The path of the database file + IO::Path(Str) :$db-file = $blog-dir.add("db.json"), + #| The date/time the post should be recorded as posted at + DateTime(Str) :$posted-at = DateTime.now, + #| Should the post be hidden from the archive? + Bool :$hidden = False, +) { + my $db = load-db $db-file; + my $id = + $db.insert-post: + DB::MarkdownPost.new( + source => $source.absolute.IO, + posted-at => $posted-at, + hidden => $hidden, + ); + write-db $db-file, $db; + say 'Post inserted with id ', $id; +} diff --git a/lib/DB.rakumod b/lib/DB.rakumod index a242fce..9d3f5dc 100644 --- a/lib/DB.rakumod +++ b/lib/DB.rakumod @@ -17,15 +17,37 @@ class BlogMeta is json(:pretty) { #| Shared post meta-data role Post is json { #| The location of the source file for the post - has IO::Path:D $.source is required; + has + IO::Path:D $.source + is required + is json( + :to-json(*.Str), + :from-json(*.IO) + ); #| The time to display for the creation of the post - has DateTime:D $.posted-at is required; + has + DateTime:D $.posted-at + is required + is json( + :to-json(*.Str), + :from-json(*.DateTime) + ); #| An optional list of edit times for the post - has DateTime:D @.edited-at = []; + has + DateTime:D @.edited-at + is json( + :to-json( + value => { $^value.Str } + ), + :from-json( + value => { $^value.DateTime } + ) + ) + = []; #| An optional list of extra slugs to use for this post - has Str:D @.slugs = []; + has Str:D @.slugs is json = []; #| Should the post be hidden from the main list - has Bool:D $.hidden is rw = False; + has Bool:D $.hidden is json is rw = False; #| Get the title for this post, intended to be extracted from whatever #| document produced it @@ -37,6 +59,7 @@ role Post is json { my $long-title-slug = self.title.lc.subst: /\h*/, '-'; return [$long-title-slug, @!slugs].flat.Array; } + } #| A plain markdown post @@ -63,5 +86,21 @@ class PostDB is json(:pretty) { #| The metadat for the blog has BlogMeta:D $.meta is required; #| A mapping from post ids to posts - has Hash[Int:D, Post:D] %.posts = %(); + has %.posts{Int:D} of MarkdownPost:D = %(); + + #| Get the next unused post ID + method next-post-id(--> Int) { + if %!posts { + %!posts.keys.max + 1 + } else { + 0 + } + } + + #| Insert a new post to the DB, returning its id + method insert-post(Post:D $post --> Int) { + my $id = self.next-post-id; + %!posts{$id} = $post; + $id + } }