Files
zhdiary/packages/nuxt/server/db.ts
T
2020-12-15 18:42:00 +07:00

100 lines
2.6 KiB
TypeScript

import sqlite3 from 'better-sqlite3'
import * as z from 'zod'
const zMatter = z.object({
date: z.date().optional(),
createdAt: z.date().optional(),
updatedAt: z.date().optional(),
title: z.string(),
image: z.string().optional(),
tag: z.array(z.string()).optional(),
category: z.string().optional(),
})
export type IMatter = z.infer<typeof zMatter>
export const zPost = z
.object({
path: z.string(),
/**
* Cleaned and jieba-separated markdown
*/
content: z.string(),
excerptHtml: z.string(),
contentHtml: z.string(),
})
.merge(zMatter.nonstrict())
export type IPost = z.infer<typeof zPost>
export class Database {
db: sqlite3.Database
constructor(public filepath: string, opts?: sqlite3.Options) {
this.db = sqlite3(filepath, opts)
}
public init(): void {
this.db.exec(/* sql */ `
CREATE TABLE IF NOT EXISTS files (
[path] TEXT PRIMARY KEY,
[date] INT, -- epoch milli
[createdAt] INT, -- epoch milli
[updatedAt] INT, -- epoch milli
-- q.title
[image] TEXT,
-- q.tag.split(/ /g)
-- q.category
-- q.content
excerptHtml TEXT NOT NULL,
contentHtml TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS files_date ON files([date]);
CREATE INDEX IF NOT EXISTS files_createdAt ON files(createdAt);
CREATE INDEX IF NOT EXISTS files_updatedAt ON files(updatedAt);
`)
this.db.exec(/* sql */ `
CREATE VIRTUAL TABLE IF NOT EXISTS q USING fts5 (
[path], -- REFERENCES files([path])
title,
tag, -- space separated
category, -- can compare via equal
content -- cleaned markdown
);
`)
}
public insert(...ps: IPost[]): void {
const fStmt = this.db.prepare(/* sql */ `
INSERT INTO files ([path], [date], [createdAt], [updatedAt], [image], excerptHtml, contentHtml)
VALUES (@path, @date, @createdAt, @updatedAt, @image, @excerptHtml, @contentHtml)
`)
const qStmt = this.db.prepare(/* sql */ `
INSERT INTO q ([path], title, tag, category, content)
VALUES (@path, @title, @tag, @category, @content)
`)
this.db.transaction(() => {
// eslint-disable-next-line array-callback-return
ps.map((p) => {
p = zPost.parse(p)
fStmt.run({
...p,
date: p.date ? p.date.getTime() : undefined,
createdAt: p.createdAt ? p.createdAt.getTime() : undefined,
updatedAt: p.updatedAt ? p.updatedAt.getTime() : undefined,
})
qStmt.run({
...p,
tag: p.tag ? p.tag.join(' ') : undefined,
})
})
})()
}
}