feat(db): migration and database setup
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import { md5 } from "@basango/encryption";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { v7 as uuidV7 } from "uuid";
|
||||
|
||||
import { Database } from "@/client";
|
||||
import { ArticleMetadata, Sentiment, TokenStatistics, article } from "@/schema";
|
||||
import { computeReadingTime, computeTokenStatistics } from "@/utils/computed";
|
||||
|
||||
import { getSourceIdByName } from "./sources";
|
||||
|
||||
export type CreateArticleParams = {
|
||||
title: string;
|
||||
body: string;
|
||||
categories: string[];
|
||||
link: string;
|
||||
sourceId: string;
|
||||
publishedAt: Date;
|
||||
sentiment?: Sentiment;
|
||||
tokenStatistics?: TokenStatistics;
|
||||
readingTime?: number;
|
||||
metadata?: ArticleMetadata;
|
||||
};
|
||||
|
||||
export async function createArticle(db: Database, params: CreateArticleParams) {
|
||||
const data = {
|
||||
...params,
|
||||
hash: md5(params.link),
|
||||
readingTime: computeReadingTime(params.body),
|
||||
sentiment: "neutral" as Sentiment,
|
||||
sourceId: await getSourceIdByName(db, params.sourceId),
|
||||
tokenStatistics: computeTokenStatistics({
|
||||
body: params.body,
|
||||
categories: params.categories,
|
||||
title: params.title,
|
||||
}),
|
||||
};
|
||||
|
||||
const duplicated = await getArticleByHash(db, data.hash);
|
||||
if (duplicated !== undefined) {
|
||||
return {
|
||||
id: duplicated.id,
|
||||
sourceId: duplicated.sourceId,
|
||||
};
|
||||
}
|
||||
|
||||
const [result] = await db
|
||||
.insert(article)
|
||||
.values({ id: uuidV7(), ...data })
|
||||
.returning({
|
||||
id: article.id,
|
||||
sourceId: article.sourceId,
|
||||
});
|
||||
|
||||
if (result === undefined) {
|
||||
throw new Error("Failed to create article");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function getArticleByHash(db: Database, hash: string) {
|
||||
return db.query.article.findFirst({
|
||||
where: eq(article.hash, hash),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import { eq } from "drizzle-orm";
|
||||
import { v7 as uuidV7 } from "uuid";
|
||||
|
||||
import { Database } from "@/client";
|
||||
import { NotFoundError } from "@/errors";
|
||||
import { Credibility, source } from "@/schema";
|
||||
|
||||
export type CreateSourceParams = {
|
||||
name: string;
|
||||
url: string;
|
||||
displayName?: string;
|
||||
description?: string;
|
||||
credibility: Credibility;
|
||||
updatedAt?: Date;
|
||||
};
|
||||
|
||||
export async function createSource(db: Database, params: CreateSourceParams) {
|
||||
const [result] = await db
|
||||
.insert(source)
|
||||
.values({ id: uuidV7(), ...params })
|
||||
.returning();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export type DeleteSourceParams = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
export async function deleteSource(db: Database, params: DeleteSourceParams) {
|
||||
const [result] = await db.delete(source).where(eq(source.id, params.id)).returning();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function getSourceByName(db: Database, name: string) {
|
||||
return db.query.source.findFirst({
|
||||
where: eq(source.name, name),
|
||||
});
|
||||
}
|
||||
|
||||
export async function getSourceIdByName(db: Database, name: string): Promise<string> {
|
||||
const result = await db.query.source.findFirst({
|
||||
columns: {
|
||||
id: true,
|
||||
},
|
||||
where: eq(source.name, name),
|
||||
});
|
||||
|
||||
if (!result) {
|
||||
throw new NotFoundError(`Source with name "${name}" not found`);
|
||||
}
|
||||
|
||||
return result.id;
|
||||
}
|
||||
|
||||
export type GetSourceByIdParams = {
|
||||
id: string;
|
||||
};
|
||||
|
||||
export async function getSourceById(db: Database, params: GetSourceByIdParams) {
|
||||
return db.query.source.findFirst({
|
||||
where: eq(source.id, params.id),
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user