init the database and move posts into the sqlite database.
This commit is contained in:
parent
27e7c8f17b
commit
908141aeff
BIN
db/blog.sqlite
Normal file
BIN
db/blog.sqlite
Normal file
Binary file not shown.
@ -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"
|
||||||
},
|
},
|
||||||
|
@ -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';
|
||||||
|
@ -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;
|
||||||
|
});
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -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
|
|
||||||
};
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
|
|
||||||
export class PostRepository {
|
|
||||||
|
|
||||||
}
|
|
19
src/services/repository/post-repository.ts
Normal file
19
src/services/repository/post-repository.ts
Normal 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 {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user