fix(app): remove legacy and scoped namespace alias

This commit is contained in:
2025-11-14 11:56:34 +02:00
parent 085851527e
commit 4ec2a608b1
681 changed files with 655 additions and 36825 deletions
+1 -2
View File
@@ -17,9 +17,8 @@
"drizzle-kit": "^0.31.6"
},
"exports": {
".": "./src/index.ts",
"./client": "./src/client.ts",
"./importer": "./src/importer/index.ts",
"./errors": "./src/errors.ts",
"./queries": "./src/queries/index.ts",
"./schema": "./src/schema.ts",
"./utils": "./src/utils/index.ts"
+2 -2
View File
@@ -1,8 +1,8 @@
import { drizzle } from "drizzle-orm/node-postgres";
import { Pool } from "pg";
import { env } from "@/config";
import * as schema from "@/schema";
import { env } from "#db/config";
import * as schema from "#db/schema";
const isDevelopment = process.env.NODE_ENV === "development";
-5
View File
@@ -1,5 +0,0 @@
export * from "./client";
export * from "./constants";
export * from "./queries";
export * from "./schema";
export * from "./utils";
+20 -11
View File
@@ -1,12 +1,11 @@
import { md5 } from "@basango/encryption";
import { eq } from "drizzle-orm";
import { count, 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";
import { Database } from "#db/client";
import { getSourceIdByName } from "#db/queries/sources";
import { ArticleMetadata, Sentiment, TokenStatistics, articles } from "#db/schema";
import { computeReadingTime, computeTokenStatistics } from "#db/utils/computed";
export type CreateArticleParams = {
title: string;
@@ -44,11 +43,11 @@ export async function createArticle(db: Database, params: CreateArticleParams) {
}
const [result] = await db
.insert(article)
.insert(articles)
.values({ id: uuidV7(), ...data })
.returning({
id: article.id,
sourceId: article.sourceId,
id: articles.id,
sourceId: articles.sourceId,
});
if (result === undefined) {
@@ -59,7 +58,17 @@ export async function createArticle(db: Database, params: CreateArticleParams) {
}
export async function getArticleByHash(db: Database, hash: string) {
return db.query.article.findFirst({
where: eq(article.hash, hash),
return await db.query.articles.findFirst({
where: eq(articles.hash, hash),
});
}
export async function countArticlesBySourceId(db: Database, sourceId: string) {
const result = await db
.select({ count: count(articles.id) })
.from(articles)
.where(eq(articles.sourceId, sourceId))
.then((res) => res[0]);
return result?.count ?? 0;
}
+29 -33
View File
@@ -2,23 +2,23 @@ import { endOfDay, startOfDay, subDays } from "date-fns";
import { eq, sql } from "drizzle-orm";
import { v7 as uuidV7 } from "uuid";
import { Database } from "@/client";
import { CATEGORY_SHARES_LIMIT, PUBLICATION_GRAPH_DAYS, TIMEZONE } from "@/constants";
import { NotFoundError } from "@/errors";
import { Credibility, article, source } from "@/schema";
import { Database } from "#db/client";
import { CATEGORY_SHARES_LIMIT, PUBLICATION_GRAPH_DAYS, TIMEZONE } from "#db/constants";
import { NotFoundError } from "#db/errors";
import { Credibility, articles, sources } from "#db/schema";
import { countArticlesBySourceId } from "./articles";
export async function getSources(db: Database) {
const rows = await db.query.source.findMany();
const rows = await db.query.sources.findMany();
const data = await Promise.all(
rows.map(async (it) => ({
...it,
categoryShares: await getCategoryShares(db, it.id),
publicationGraph: await getPublicationGraph(db, it.id),
return await Promise.all(
rows.map(async (row) => ({
...row,
articles: await countArticlesBySourceId(db, row.id),
publicationGraph: await getSourcePublicationGraph(db, row.id),
})),
);
return data;
}
export type CreateSourceParams = {
@@ -31,7 +31,7 @@ export type CreateSourceParams = {
export async function createSource(db: Database, params: CreateSourceParams) {
const [result] = await db
.insert(source)
.insert(sources)
.values({ id: uuidV7(), ...params })
.returning();
@@ -48,14 +48,14 @@ export type UpdateSourceParams = {
export async function updateSource(db: Database, params: UpdateSourceParams) {
const [result] = await db
.update(source)
.update(sources)
.set({
credibility: params.credibility,
description: params.description,
displayName: params.displayName,
name: params.name,
})
.where(eq(source.id, params.id))
.where(eq(sources.id, params.id))
.returning();
if (result === undefined) {
@@ -70,39 +70,35 @@ export type DeleteSourceParams = {
};
export async function deleteSource(db: Database, params: DeleteSourceParams) {
const [result] = await db.delete(source).where(eq(source.id, params.id)).returning();
const [result] = await db.delete(sources).where(eq(sources.id, params.id)).returning();
return result;
}
export async function getSourceByName(db: Database, name: string) {
return db.query.source.findFirst({
where: eq(source.name, name),
return await db.query.sources.findFirst({
where: eq(sources.name, name),
});
}
export async function getSourceById(db: Database, id: string) {
const item = db.query.source.findFirst({
where: eq(source.id, id),
const item = await db.query.sources.findFirst({
where: eq(sources.id, id),
});
if (item === undefined) {
throw new NotFoundError("Source not found");
}
return {
...item,
categoryShares: await getCategoryShares(db, id),
publicationGraph: await getPublicationGraph(db, id),
};
return item;
}
export async function getSourceIdByName(db: Database, name: string): Promise<string> {
const result = await db.query.source.findFirst({
const result = await db.query.sources.findFirst({
columns: {
id: true,
},
where: eq(source.name, name),
where: eq(sources.name, name),
});
if (!result) {
@@ -137,7 +133,7 @@ export type CategoryShares = {
total: number;
};
export async function getPublicationGraph(
export async function getSourcePublicationGraph(
db: Database,
id: string,
days: number = PUBLICATION_GRAPH_DAYS,
@@ -145,7 +141,7 @@ export async function getPublicationGraph(
const endDate = endOfDay(new Date());
const startDate = startOfDay(subDays(endDate, days - 1));
const data = await db.execute<{ date: string; count: number }>(sql`
const data = await db.execute<PublicationEntry>(sql`
WITH bounds AS (
SELECT
${startDate}::timestamptz AS start_ts,
@@ -181,7 +177,7 @@ export async function getPublicationGraph(
return { items: data.rows, total: data.rows.length };
}
async function getCategoryShares(db: Database, id: string): Promise<CategoryShares> {
export async function getSourceCategoryShares(db: Database, id: string): Promise<CategoryShares> {
const data = await db.execute<CategoryShare>(sql`
SELECT
cat AS category,
@@ -189,9 +185,9 @@ async function getCategoryShares(db: Database, id: string): Promise<CategoryShar
ROUND((COUNT(*)::numeric / SUM(COUNT(*)) OVER ()) * 100, 2) AS percentage
FROM (
SELECT NULLIF(BTRIM(c), '') AS cat
FROM ${article}
CROSS JOIN LATERAL UNNEST(COALESCE(${article.categories}, ARRAY[]::text[])) AS c
WHERE ${article.sourceId} = ${id}
FROM ${articles}
CROSS JOIN LATERAL UNNEST(COALESCE(${articles.categories}, ARRAY[]::text[])) AS c
WHERE ${articles.sourceId} = ${id}
) t
WHERE cat IS NOT NULL
GROUP BY cat
+72 -72
View File
@@ -120,7 +120,7 @@ export type GeneratedCode = string;
/* Tables */
/* -------------------------------------------------------------------------- */
export const user = pgTable(
export const users = pgTable(
"user",
{
createdAt: timestamp("created_at").defaultNow().notNull(),
@@ -144,7 +144,7 @@ export const user = pgTable(
],
);
export const source = pgTable(
export const sources = pgTable(
"source",
{
credibility: jsonb("credibility").$type<Credibility>(),
@@ -161,7 +161,7 @@ export const source = pgTable(
],
);
export const article = pgTable(
export const articles = pgTable(
"article",
{
body: text().notNull(),
@@ -205,7 +205,7 @@ export const article = pgTable(
uniqueIndex("unq_article_hash").using("btree", table.hash.asc().nullsLast()),
foreignKey({
columns: [table.sourceId],
foreignColumns: [source.id],
foreignColumns: [sources.id],
name: "fk_article_source_id",
}).onDelete("cascade"),
check("chk_article_reading_time", sql`(reading_time >= 0)`),
@@ -220,7 +220,7 @@ export const article = pgTable(
],
);
export const bookmark = pgTable(
export const bookmarks = pgTable(
"bookmark",
{
createdAt: timestamp("created_at").defaultNow().notNull(),
@@ -244,13 +244,13 @@ export const bookmark = pgTable(
),
foreignKey({
columns: [table.userId],
foreignColumns: [user.id],
foreignColumns: [users.id],
name: "fk_bookmark_user_id",
}).onDelete("cascade"),
],
);
export const bookmarkArticle = pgTable(
export const bookmarkArticles = pgTable(
"bookmark_article",
{
articleId: uuid("article_id").notNull(),
@@ -261,18 +261,18 @@ export const bookmarkArticle = pgTable(
index("idx_bookmark_article_bookmark_id").using("btree", table.bookmarkId.asc().nullsLast()),
foreignKey({
columns: [table.bookmarkId],
foreignColumns: [bookmark.id],
foreignColumns: [bookmarks.id],
name: "fk_bookmark_article_bookmark_id",
}).onDelete("cascade"),
foreignKey({
columns: [table.articleId],
foreignColumns: [article.id],
foreignColumns: [articles.id],
name: "fk_bookmark_article_article_id",
}).onDelete("cascade"),
],
);
export const loginAttempt = pgTable(
export const loginAttempts = pgTable(
"login_attempt",
{
createdAt: timestamp("created_at").defaultNow().notNull(),
@@ -287,7 +287,7 @@ export const loginAttempt = pgTable(
),
foreignKey({
columns: [table.userId],
foreignColumns: [user.id],
foreignColumns: [users.id],
name: "fk_login_attempt_user_id",
}).onDelete("cascade"),
],
@@ -312,13 +312,13 @@ export const loginHistory = pgTable(
index("idx_login_history_ip_address").using("btree", table.ipAddress.asc().nullsLast()),
foreignKey({
columns: [table.userId],
foreignColumns: [user.id],
foreignColumns: [users.id],
name: "fk_login_history_user_id",
}).onDelete("cascade"),
],
);
export const verificationToken = pgTable(
export const verificationTokens = pgTable(
"verification_token",
{
createdAt: timestamp("created_at").defaultNow().notNull(),
@@ -337,13 +337,13 @@ export const verificationToken = pgTable(
.where(sql`${table.token} IS NOT NULL`),
foreignKey({
columns: [table.userId],
foreignColumns: [user.id],
foreignColumns: [users.id],
name: "fk_verification_token_user_id",
}).onDelete("cascade"),
],
);
export const followedSource = pgTable(
export const followedSources = pgTable(
"followed_source",
{
createdAt: timestamp("created_at").defaultNow().notNull(),
@@ -366,18 +366,18 @@ export const followedSource = pgTable(
),
foreignKey({
columns: [table.followerId],
foreignColumns: [user.id],
foreignColumns: [users.id],
name: "fk_followed_source_follower_id",
}).onDelete("cascade"),
foreignKey({
columns: [table.sourceId],
foreignColumns: [source.id],
foreignColumns: [sources.id],
name: "fk_followed_source_source_id",
}).onDelete("cascade"),
],
);
export const comment = pgTable(
export const comments = pgTable(
"comment",
{
articleId: uuid("article_id").notNull(),
@@ -398,18 +398,18 @@ export const comment = pgTable(
),
foreignKey({
columns: [table.userId],
foreignColumns: [user.id],
foreignColumns: [users.id],
name: "fk_comment_user_id",
}).onDelete("cascade"),
foreignKey({
columns: [table.articleId],
foreignColumns: [article.id],
foreignColumns: [articles.id],
name: "fk_comment_article_id",
}).onDelete("cascade"),
],
);
export const refreshToken = pgTable(
export const refreshTokens = pgTable(
"refresh_token",
{
id: uuid().primaryKey().notNull(),
@@ -428,87 +428,87 @@ export const refreshToken = pgTable(
/* Relations */
/* -------------------------------------------------------------------------- */
export const bookmarkRelations = relations(bookmark, ({ one, many }) => ({
bookmarkArticles: many(bookmarkArticle),
user: one(user, {
fields: [bookmark.userId],
references: [user.id],
export const bookmarkRelations = relations(bookmarks, ({ one, many }) => ({
bookmarkArticles: many(bookmarkArticles),
user: one(users, {
fields: [bookmarks.userId],
references: [users.id],
}),
}));
export const userRelations = relations(user, ({ many }) => ({
bookmarks: many(bookmark),
comments: many(comment),
followedSources: many(followedSource),
loginAttempts: many(loginAttempt),
export const userRelations = relations(users, ({ many }) => ({
bookmarks: many(bookmarks),
comments: many(comments),
followedSources: many(followedSources),
loginAttempts: many(loginAttempts),
loginHistories: many(loginHistory),
verificationTokens: many(verificationToken),
verificationTokens: many(verificationTokens),
}));
export const loginAttemptRelations = relations(loginAttempt, ({ one }) => ({
user: one(user, {
fields: [loginAttempt.userId],
references: [user.id],
export const loginAttemptRelations = relations(loginAttempts, ({ one }) => ({
user: one(users, {
fields: [loginAttempts.userId],
references: [users.id],
}),
}));
export const loginHistoryRelations = relations(loginHistory, ({ one }) => ({
user: one(user, {
user: one(users, {
fields: [loginHistory.userId],
references: [user.id],
references: [users.id],
}),
}));
export const verificationTokenRelations = relations(verificationToken, ({ one }) => ({
user: one(user, {
fields: [verificationToken.userId],
references: [user.id],
export const verificationTokenRelations = relations(verificationTokens, ({ one }) => ({
user: one(users, {
fields: [verificationTokens.userId],
references: [users.id],
}),
}));
export const followedSourceRelations = relations(followedSource, ({ one }) => ({
source: one(source, {
fields: [followedSource.sourceId],
references: [source.id],
export const followedSourceRelations = relations(followedSources, ({ one }) => ({
source: one(sources, {
fields: [followedSources.sourceId],
references: [sources.id],
}),
user: one(user, {
fields: [followedSource.followerId],
references: [user.id],
user: one(users, {
fields: [followedSources.followerId],
references: [users.id],
}),
}));
export const sourceRelations = relations(source, ({ many }) => ({
articles: many(article),
followedSources: many(followedSource),
export const sourceRelations = relations(sources, ({ many }) => ({
articles: many(articles),
followedSources: many(followedSources),
}));
export const commentRelations = relations(comment, ({ one }) => ({
article: one(article, {
fields: [comment.articleId],
references: [article.id],
export const commentRelations = relations(comments, ({ one }) => ({
article: one(articles, {
fields: [comments.articleId],
references: [articles.id],
}),
user: one(user, {
fields: [comment.userId],
references: [user.id],
user: one(users, {
fields: [comments.userId],
references: [users.id],
}),
}));
export const articleRelations = relations(article, ({ one, many }) => ({
bookmarkArticles: many(bookmarkArticle),
comments: many(comment),
source: one(source, {
fields: [article.sourceId],
references: [source.id],
export const articleRelations = relations(articles, ({ one, many }) => ({
bookmarkArticles: many(bookmarkArticles),
comments: many(comments),
source: one(sources, {
fields: [articles.sourceId],
references: [sources.id],
}),
}));
export const bookmarkArticleRelations = relations(bookmarkArticle, ({ one }) => ({
article: one(article, {
fields: [bookmarkArticle.articleId],
references: [article.id],
export const bookmarkArticleRelations = relations(bookmarkArticles, ({ one }) => ({
article: one(articles, {
fields: [bookmarkArticles.articleId],
references: [articles.id],
}),
bookmark: one(bookmark, {
fields: [bookmarkArticle.bookmarkId],
references: [bookmark.id],
bookmark: one(bookmarks, {
fields: [bookmarkArticles.bookmarkId],
references: [bookmarks.id],
}),
}));
+2 -2
View File
@@ -3,8 +3,8 @@
import { RowDataPacket } from "mysql2/promise";
import { Pool, PoolClient } from "pg";
import { env } from "@/config";
import { computeReadingTime } from "@/utils/computed";
import { env } from "#db/config";
import { computeReadingTime } from "#db/utils/computed";
type SourceOptions = {
host: string;
+2 -2
View File
@@ -2,8 +2,8 @@
import { Pool } from "pg";
import { env } from "@/config";
import { computeTokenStatistics } from "@/utils/computed";
import { env } from "#db/config";
import { computeTokenStatistics } from "#db/utils/computed";
type ArticleRow = {
id: string;
+1 -1
View File
@@ -1,6 +1,6 @@
import { TiktokenEncoding, get_encoding } from "tiktoken";
import { TokenStatistics } from "@/schema";
import { TokenStatistics } from "#db/schema";
/**
* Count the number of tokens in the given text using the specified encoding.
+2 -2
View File
@@ -4,7 +4,7 @@ import {
PAGINATION_DEFAULT_LIMIT,
PAGINATION_DEFAULT_PAGE,
PAGINATION_MAX_LIMIT,
} from "@/constants";
} from "#db/constants";
export interface PageRequest {
page?: number;
@@ -83,7 +83,7 @@ export function decodeCursor(cursor?: string | null): CursorPayload | null {
const decoded = Buffer.from(cursor, "base64").toString("utf8");
const payload = JSON.parse(decoded) as CursorPayload;
if (!payload || typeof payload.id !== "string" || payload.id.length === 0) {
if (!payload || payload.id.length === 0) {
return null;
}
+1 -1
View File
@@ -2,7 +2,7 @@
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
"#db/*": ["./src/*"]
}
},
"exclude": ["node_modules"],