init the database and move posts into the sqlite database.

This commit is contained in:
Dave Smith-Hayes 2024-07-11 21:37:12 -04:00
parent 27e7c8f17b
commit 908141aeff
11 changed files with 70 additions and 100 deletions

BIN
bun.lockb

Binary file not shown.

BIN
db/blog.sqlite Normal file

Binary file not shown.

View File

@ -5,8 +5,8 @@
}, },
"dependencies": { "dependencies": {
"@types/yaml-front-matter": "^4.1.3", "@types/yaml-front-matter": "^4.1.3",
"hono": "^4.4.10", "hono": "^4.4.13",
"marked": "^13.0.1", "marked": "^13.0.2",
"remark": "^15.0.1", "remark": "^15.0.1",
"yaml-front-matter": "^4.1.1" "yaml-front-matter": "^4.1.1"
}, },

View File

@ -1,3 +1,4 @@
export const POST_PATH: string = __dirname + '/../posts'; export const POST_PATH: string = __dirname + '/../posts';
export const STATIC_PATH: string = __dirname + '/../static'; export const STATIC_PATH: string = __dirname + '/../static';
export const POST_ROUTE_PREFIX: string = '/posts' export const POST_ROUTE_PREFIX: string = '/posts'
export const SQLITE_DATABASE_FILE: string = __dirname + '/../db/blog.sqlite';

View File

@ -1,13 +1,11 @@
import { readdir } from 'node:fs/promises'; import { PostFileService } from '@blog/services/post-file';
import { openPostMarkdownFile, parsePostMetadata } from '@blog/post/post-reader'; import { db } from '@blog/services/database';
import { PostMeta } from '@blog/model/PostMeta';
import db from '@blog/db/memory';
const createPostSql: string = ` const createPostSql: string = `
CREATE TABLE posts ( CREATE TABLE IF NOT EXISTS posts (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
title TEXT NOT NULL, title TEXT NOT NULL,
slug TEXT NOT NULL, slug TEXT NOT NULL UNIQUE,
is_draft INTEGER DEFAULT 0, is_draft INTEGER DEFAULT 0,
description TEXT, description TEXT,
published_date DATE, published_date DATE,
@ -16,7 +14,7 @@ CREATE TABLE posts (
`; `;
const createAuthorSql: string = ` const createAuthorSql: string = `
CREATE TABLE authors ( CREATE TABLE IF NOT EXISTS authors (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
name TEXT, name TEXT,
email TEXT email TEXT
@ -24,14 +22,14 @@ CREATE TABLE authors (
`; `;
const createTagsSql: string = ` const createTagsSql: string = `
CREATE TABLE tags ( CREATE TABLE IF NOT EXISTS tags (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
tag TEXT UNIQUE tag TEXT UNIQUE
) )
`; `;
const createPostsTagsSql: string = ` const createPostsTagsSql: string = `
CREATE TABLE posts_tags ( CREATE TABLE IF NOT EXISTS posts_tags (
tag_id TEXT, tag_id TEXT,
post_id INTEGER, post_id INTEGER,
@ -41,7 +39,7 @@ CREATE TABLE posts_tags (
`; `;
const createPostHtmlCache = ` const createPostHtmlCache = `
CREATE TABLE post_html_cache ( CREATE TABLE IF NOT EXISTS post_html_cache (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
post_id INTEGER, post_id INTEGER,
content TEXT, content TEXT,
@ -69,27 +67,44 @@ export async function setupDb(): Promise<void> {
} }
export async function readPostsToDatabase(postPath: string): Promise<void> { export async function readPostsToDatabase(): Promise<void> {
const posts = new Array(); const postService = await PostFileService.create();
const createPostSql: string = ` const createPostSql: string = `
INSERT INTO posts (title, slug, description, is_draft, published_date, raw_content) INSERT INTO posts (title, slug, description, is_draft,
VALUES ($title, $slug, $description, $is_draft, $published_date, $raw_content); published_date, raw_content)
`; VALUES ($title, $slug, $description, $is_draft,
$published_date, $raw_content);`;
const fileList = await readdir(postPath); const createPostHtmlCacheSql: string = `
for (const file of fileList) { INSERT INTO post_html_cache (post_id, content)
const contents: string = await openPostMarkdownFile(postPath + "/" + file); VALUES ($posId, $content);`;
const post = parsePostMetadata(contents);
for (const [ slug, post ] of postService.getPosts().entries()) {
const postQuery = db.prepare(createPostSql); const postQuery = db.prepare(createPostSql);
postQuery.run({ const { lastInsertRowId } = postQuery.run({
$title: post.meta.title, $title: post.meta.title,
$slug: file, $slug: slug,
$description: post.meta.description, $description: post.meta.description,
$is_draft: post.meta.draft ?? false, $is_draft: post.meta.draft ?? false,
$published_date: post.meta.date.toString(), $published_date: post.meta.date.toString(),
$raw_content: post.content $raw_content: post.content
}); });
const htmlCacheQuery = db.prepare(createPostHtmlCacheSql);
htmlCacheQuery.run({ $postId: lastInsertRowId, $content: post.html })
console.log({ message: "Added " + post.meta.title + " to the database." }); console.log({ message: "Added " + post.meta.title + " to the database." });
} }
} }
async function main() {
await setupDb();
await readPostsToDatabase();
}
main()
.then(() => process.exit(0))
.catch(e => {
console.log(e);
throw e;
});

View File

@ -1,4 +1,4 @@
import { PostMeta } from '@blog/models/PostMeta'; import { PostMeta } from '@blog/model/PostMeta';
export type Post = { export type Post = {
meta: PostMeta, meta: PostMeta,

View File

@ -1,62 +0,0 @@
import { marked } from 'marked';
import type { Post } from '@blog/models/Post';
import type { PostMeta } from '@blog/models/PostMeta';
import * as yamlFront from 'yaml-front-matter';
import { readdir } from 'node:fs/promises';
export async function openPostMarkdownFile(filename: string): Promise<string> {
const file = Bun.file(filename);
return file.text();
}
type PostMetaWithRawContent = {
meta: PostMeta,
content: string
};
export function parsePostMetadata(post: string): PostMetaWithRawContent {
const parsedData = yamlFront.loadFront(post);
return {
meta: {
title: parsedData.title,
description: parsedData.description,
date: new Date(parsedData.date),
draft: parsedData?.draft || false,
tags: parsedData.tags,
},
content: parsedData.__content
};
}
export async function getPostList(path: string): Promise<PostMeta[]> {
const postList: PostMeta[] = new Array<PostMeta>();
const dir = await readdir(path);
if (!dir.length) {
return postList;
}
for (const file of dir) {
const fileContent = await openPostMarkdownFile(path + '/' + file);
const postMeta = parsePostMetadata(fileContent);
postMeta.meta.slug = "/posts/" + file.slice(0, -3);
postList.push(postMeta.meta);
}
return postList;
}
export async function readPostMarkdown(filename: string): Promise<Post> {
const contents = await openPostMarkdownFile(filename);
const post = parsePostMetadata(contents);
post.meta.slug = "/posts/" + filename.slice(0, -3);
const parsedPost = await marked.parse(post.content);
return {
meta: post.meta,
content: post.content,
html: parsedPost
};
}

View File

@ -1,7 +1,4 @@
export type ConnectionConfig = { import { Database } from "bun:sqlite";
host: string, import { SQLITE_DATABASE_FILE } from "@blog/config";
username: string, export const db = new Database(SQLITE_DATABASE_FILE);
password: string,
database: string,
port: number
};

View File

@ -41,8 +41,8 @@ export class PostFileService {
const posts = new Map<string, Post>(); const posts = new Map<string, Post>();
const postFiles: string[] = await readdir(POST_PATH); const postFiles: string[] = await readdir(POST_PATH);
for (const postFile in postFiles) { for (const postFile of postFiles) {
const post = await readPostFile(postFile); const post = await readPostFile(POST_PATH + "/" + postFile);
const key = post.meta?.slug || postFile.slice(0, -3); const key = post.meta?.slug || postFile.slice(0, -3);
posts.set(key, post); posts.set(key, post);
} }
@ -50,6 +50,10 @@ export class PostFileService {
return new PostFileService(posts); return new PostFileService(posts);
} }
public getPosts(): Map<string, Post> {
return this.posts;
}
public getPost(slug: string): Post { public getPost(slug: string): Post {
const post = this.posts.get(slug); const post = this.posts.get(slug);

View File

@ -1,4 +0,0 @@
export class PostRepository {
}

View File

@ -0,0 +1,19 @@
import { Post } from '@blog/models/Post';
import { db } from '@blog/services/database';
export class PostRepository {
public async getPost(id: number): Promise<Post> {
const queryString = `
SELECT title, slug, is_draft, description, published_date, raw_content
FROM posts
WHERE id = $id
`;
const query = db.query(queryString);
const post = query.get({ $id: id }).as(Post);
return post;
}
public async getPostBySlug(slug: string): Post {
}
}