From d3cc3145e06a4c78ec46790b8b2283a5892049eb Mon Sep 17 00:00:00 2001 From: Hare Date: Wed, 28 Aug 2024 00:13:46 +0900 Subject: [PATCH] feat: Add database connection handling to server hooks --- src/app.d.ts | 6 +- src/hooks.server.ts | 10 ++ src/lib/server/database.ts | 27 ++-- src/lib/server/database/get_connection.ts | 15 +++ src/lib/server/database/init_db.ts | 126 +++++++++--------- src/routes/+page.server.ts | 4 +- .../article/[category]/[id]/+page.server.ts | 4 +- .../[category]/[series]/[id]/+page.server.ts | 4 +- 8 files changed, 109 insertions(+), 87 deletions(-) create mode 100644 src/hooks.server.ts create mode 100644 src/lib/server/database/get_connection.ts diff --git a/src/app.d.ts b/src/app.d.ts index 743f07b..ee8bd52 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -1,9 +1,13 @@ // See https://kit.svelte.dev/docs/types#app // for information about these interfaces +import { Database } from 'pg'; + declare global { namespace App { // interface Error {} - // interface Locals {} + interface Locals { + db: any; + } // interface PageData {} // interface PageState {} // interface Platform {} diff --git a/src/hooks.server.ts b/src/hooks.server.ts new file mode 100644 index 0000000..9ed28ca --- /dev/null +++ b/src/hooks.server.ts @@ -0,0 +1,10 @@ +import type { Handle } from '@sveltejs/kit' +import { getConnection } from '$lib/server/database/get_connection' + +export const handle: Handle = async ({ event, resolve }) => { + const pg = getConnection(); + event.locals.db = pg; + + const result = await resolve(event); + return result; +} \ No newline at end of file diff --git a/src/lib/server/database.ts b/src/lib/server/database.ts index 8e642f4..e8bcae5 100644 --- a/src/lib/server/database.ts +++ b/src/lib/server/database.ts @@ -1,21 +1,12 @@ import pg from 'pg'; -const { Pool } = pg; +import { Pool } from 'pg'; +import { getConnection } from './database/get_connection'; -import { - PG_USER, - PG_PASS, - PG_HOST, - PG_PORT, - PG_DB, -} from '$env/static/private' -const connectionString = `postgres://${PG_USER}:${PG_PASS}@${PG_HOST}:${PG_PORT}/${PG_DB}`; - -const pool = new Pool({ connectionString }); -class Postgres { +export class Postgres { client: pg.PoolClient | null = null; - public static async new() { + public static async new(pool: Pool) { const pg = new Postgres(); - pg.client = await pool.connect(); + pg.client = await getConnection().connect(); return pg; } @@ -40,8 +31,10 @@ class Postgres { } } -export default async () => { return await Postgres.new(); } - +export default async ( + pool: Pool +) => { return await Postgres.new(pool); }; +import { building } from '$app/environment'; import init from '$lib/server/database/init_db'; -await init(); +if (!building) await init(await Postgres.new(getConnection())); diff --git a/src/lib/server/database/get_connection.ts b/src/lib/server/database/get_connection.ts new file mode 100644 index 0000000..8e65981 --- /dev/null +++ b/src/lib/server/database/get_connection.ts @@ -0,0 +1,15 @@ +import pg from 'pg'; +const { Pool } = pg; + +import { + PG_USER, + PG_PASS, + PG_HOST, + PG_PORT, + PG_DB, +} from '$env/static/private' +const connectionString = `postgres://${PG_USER}:${PG_PASS}@${PG_HOST}:${PG_PORT}/${PG_DB}`; + +const pool = new Pool({ connectionString }); + +export const getConnection = () => pool; diff --git a/src/lib/server/database/init_db.ts b/src/lib/server/database/init_db.ts index b96f03c..45ef903 100644 --- a/src/lib/server/database/init_db.ts +++ b/src/lib/server/database/init_db.ts @@ -1,10 +1,9 @@ // initialize import PG from '$lib/server/database'; +import type { Postgres } from '$lib/server/database'; import fs from 'fs'; import { compile } from 'mdsvex'; - -export default async function init() { - +export default async function init(db: Postgres) { // Create tables(when not exists) const schemas = [ { @@ -73,9 +72,9 @@ export default async function init() { } ]; - const db = await PG(); + await db.begin(); try { - await db.begin(); + // Create tables for (const schema of schemas) { const res = await db.query(`select * from information_schema.tables where table_name = '${schema.name}'`) if (res.rowCount == 0) { @@ -87,68 +86,69 @@ export default async function init() { } } await db.commit(); + + const articleFiles: ArticleFileItem[] = []; + function scanDir(path: string) { + const files = fs.readdirSync(path); + for (const file of files) { + const dir = `${path}/${file}`; + const stat = fs.statSync(dir); + if (stat.isDirectory()) { + scanDir(dir); + } else { + articleFiles.push({ path: `${path}/${file}`, id: file }); + } + } + } + scanDir('./articles/article'); + + await db.query('update tag set ref_count = 0'); + db.commit(); + + for (const { path, id } of articleFiles) { + const res = await db.query('select * from article where id = $1', [id]); + const compiled = await compile(fs.readFileSync(path, 'utf-8')); + const title = compiled.data.fm.title; + const category = path.split('/')[3]; + const tags: string[] = compiled.data.fm.tags; + const released_at = new Date(compiled.data.fm.released_at); + const updated_at = new Date(compiled.data.fm.updated_at); + const image = compiled.data.fm.image; + const publish = compiled.data.fm.publish; + const content = compiled.code + .replace(/>{@html ``}<\/pre>/g, ''); + if (res.rowCount == 0) { + console.log(`New article: ${id}`); + await db.query( + 'insert into article (id, title, category, released_at, updated_at, tags, image, publish, content) values ($1, $2, $3, $4, $5, $6, $7, $8, $9)', + [id, title, category, released_at, updated_at, tags, image, publish, content] + ); + } else if (res.rows[0].updated_at < updated_at) { + console.log(`Update article: ${id}`); + await db.query( + 'update article set title = $2, updated_at = $4, tags = $5, content = $6 where id = $1', + [id, title, updated_at, tags, content] + ); + } else { + console.log(`Article ${id} is already up-to-date`); + } + for (const tag of tags) { + if ((await db.query('select * from tag where name = $1', [tag])).rowCount == 0) { + db.query('insert into tag (name, ref_count) values ($1, 1)', [tag]); + } else { + db.query('update tag set ref_count = ref_count + 1 where name = $1', [tag]); + } + } + } + await db.commit(); + } catch (err) { console.error(err); await db.rollback(); + } finally { + await db.release(); } - - const articleFiles: ArticleFileItem[] = []; - function scanDir(path: string) { - const files = fs.readdirSync(path); - for (const file of files) { - const dir = `${path}/${file}`; - const stat = fs.statSync(dir); - if (stat.isDirectory()) { - scanDir(dir); - } else { - articleFiles.push({ path: `${path}/${file}`, id: file }); - } - } - } - scanDir('./articles/article'); - - await db.query('update tag set ref_count = 0'); - db.commit(); - - for (const { path, id } of articleFiles) { - const res = await db.query('select * from article where id = $1', [id]); - const compiled = await compile(fs.readFileSync(path, 'utf-8')); - const title = compiled.data.fm.title; - const category = path.split('/')[3]; - const tags: string[] = compiled.data.fm.tags; - const released_at = new Date(compiled.data.fm.released_at); - const updated_at = new Date(compiled.data.fm.updated_at); - const image = compiled.data.fm.image; - const publish = compiled.data.fm.publish; - const content = compiled.code - .replace(/>{@html ``}<\/pre>/g, ''); - if (res.rowCount == 0) { - console.log(`New article: ${id}`); - await db.query( - 'insert into article (id, title, category, released_at, updated_at, tags, image, publish, content) values ($1, $2, $3, $4, $5, $6, $7, $8, $9)', - [id, title, category, released_at, updated_at, tags, image, publish, content] - ); - } else if (res.rows[0].updated_at < updated_at) { - console.log(`Update article: ${id}`); - await db.query( - 'update article set title = $2, updated_at = $4, tags = $5, content = $6 where id = $1', - [id, title, updated_at, tags, content] - ); - } else { - console.log(`Article ${id} is already up-to-date`); - } - for (const tag of tags) { - if ((await db.query('select * from tag where name = $1', [tag])).rowCount == 0) { - db.query('insert into tag (name, ref_count) values ($1, 1)', [tag]); - } else { - db.query('update tag set ref_count = ref_count + 1 where name = $1', [tag]); - } - } - } - - await db.commit(); - await db.release(); } type ArticleFileItem = { diff --git a/src/routes/+page.server.ts b/src/routes/+page.server.ts index ebb36da..35af34e 100644 --- a/src/routes/+page.server.ts +++ b/src/routes/+page.server.ts @@ -18,8 +18,8 @@ let data: { updated: "", }; -export const load: PageServerLoad = async ({ params }) => { - const db = await PG(); +export const load: PageServerLoad = async ({ params, locals }) => { + const db = await PG(locals.db); await db.begin(); try { const recent_articles = await db.query( diff --git a/src/routes/article/[category]/[id]/+page.server.ts b/src/routes/article/[category]/[id]/+page.server.ts index c7c9759..f7e4fee 100644 --- a/src/routes/article/[category]/[id]/+page.server.ts +++ b/src/routes/article/[category]/[id]/+page.server.ts @@ -3,11 +3,11 @@ import type { PageServerLoad } from './$types'; import PG from '$lib/server/database'; import { error } from '@sveltejs/kit'; -export const load: PageServerLoad = async ({ params }) => { +export const load: PageServerLoad = async ({ params, locals }) => { const { category, id } = params; console.log(id); - const db = await PG(); + const db = await PG(locals.db); await db.begin(); try { const article = await db.query( diff --git a/src/routes/article/[category]/[series]/[id]/+page.server.ts b/src/routes/article/[category]/[series]/[id]/+page.server.ts index 50dfac0..75af536 100644 --- a/src/routes/article/[category]/[series]/[id]/+page.server.ts +++ b/src/routes/article/[category]/[series]/[id]/+page.server.ts @@ -3,11 +3,11 @@ import type { PageServerLoad } from './$types'; import PG from '$lib/server/database'; import { error } from '@sveltejs/kit'; -export const load: PageServerLoad = async ({ params }) => { +export const load: PageServerLoad = async ({ params, locals }) => { const { category, id, series } = params; console.log(id); - const db = await PG(); + const db = await PG(locals.db); await db.begin(); try { const article = await db.query(