Refactor config management to use Drizzle ORM

- Replaced Sequelize with Drizzle ORM in config-related routes and models.
- Updated database queries to use Drizzle's syntax for selecting, inserting, updating, and deleting configurations.
- Removed the ConfigModel class and replaced it with direct database interactions.
- Introduced nanoid for generating unique IDs for new configurations.
- Added new routes for managing marks, including CRUD operations and versioning.
- Implemented transaction handling for critical operations in the MarkModel.
- Enhanced error handling and validation in routes.
This commit is contained in:
2026-02-05 16:31:09 +08:00
parent 5200cf4c38
commit 266b7b33de
13 changed files with 924 additions and 191 deletions

308
src/routes/mark/list.ts Normal file
View File

@@ -0,0 +1,308 @@
import { eq, desc, and, like, or, count, sql } from 'drizzle-orm';
import { app, db, schema } from '../../app.ts';
import { MarkServices } from './services/mark.ts';
import dayjs from 'dayjs';
import { nanoid } from 'nanoid';
app
.route({
path: 'mark',
key: 'list',
description: 'mark list.',
middleware: ['auth'],
})
.define(async (ctx) => {
const tokenUser = ctx.state.tokenUser;
ctx.body = await MarkServices.getList({
uid: tokenUser.id,
query: ctx.query,
queryType: 'simple',
});
})
.addTo(app);
app
.route({
path: 'mark',
key: 'getVersion',
middleware: ['auth'],
})
.define(async (ctx) => {
const tokenUser = ctx.state.tokenUser;
const { id } = ctx.query;
if (id) {
const marks = await db.select().from(schema.microMark).where(eq(schema.microMark.id, id)).limit(1);
const markModel = marks[0];
if (!markModel) {
ctx.throw(404, 'mark not found');
}
if (markModel.uid !== tokenUser.id) {
ctx.throw(403, 'no permission');
}
ctx.body = {
version: Number(markModel.version),
updatedAt: markModel.updatedAt,
createdAt: markModel.createdAt,
id: markModel.id,
};
} else {
ctx.throw(400, 'id is required');
// const [markModel, created] = await MarkModel.findOrCreate({
// where: {
// uid: tokenUser.id,
// puid: tokenUser.uid,
// title: dayjs().format('YYYY-MM-DD'),
// },
// defaults: {
// title: dayjs().format('YYYY-MM-DD'),
// uid: tokenUser.id,
// markType: 'wallnote',
// tags: ['daily'],
// },
// });
// ctx.body = {
// version: Number(markModel.version),
// updatedAt: markModel.updatedAt,
// createdAt: markModel.createdAt,
// id: markModel.id,
// created: created,
// };
}
})
.addTo(app);
app
.route({
path: 'mark',
key: 'get',
middleware: ['auth'],
})
.define(async (ctx) => {
const tokenUser = ctx.state.tokenUser;
const { id } = ctx.query;
if (id) {
const marks = await db.select().from(schema.microMark).where(eq(schema.microMark.id, id)).limit(1);
const markModel = marks[0];
if (!markModel) {
ctx.throw(404, 'mark not found');
}
if (markModel.uid !== tokenUser.id) {
ctx.throw(403, 'no permission');
}
ctx.body = markModel;
} else {
ctx.throw(400, 'id is required');
// id 不存在获取当天的title为 日期的一条数据
// const [markModel, created] = await MarkModel.findOrCreate({
// where: {
// uid: tokenUser.id,
// puid: tokenUser.uid,
// title: dayjs().format('YYYY-MM-DD'),
// },
// defaults: {
// title: dayjs().format('YYYY-MM-DD'),
// uid: tokenUser.id,
// markType: 'wallnote',
// tags: ['daily'],
// uname: tokenUser.username,
// puid: tokenUser.uid,
// version: 1,
// },
// });
// ctx.body = markModel;
}
})
.addTo(app);
app
.route({
path: 'mark',
key: 'update',
middleware: ['auth'],
isDebug: true,
})
.define(async (ctx) => {
const tokenUser = ctx.state.tokenUser;
const { id, createdAt, updatedAt, uid: _, puid: _2, uname: _3, data, ...rest } = ctx.query.data || {};
let markModel: any;
if (id) {
const marks = await db.select().from(schema.microMark).where(eq(schema.microMark.id, id)).limit(1);
markModel = marks[0];
if (!markModel) {
ctx.throw(404, 'mark not found');
}
if (markModel.uid !== tokenUser.id) {
ctx.throw(403, 'no permission');
}
const version = Number(markModel.version) + 1;
const updated = await db.update(schema.microMark)
.set({
...rest,
data: {
...(markModel.data as any || {}),
...data,
},
version,
updatedAt: new Date().toISOString(),
})
.where(eq(schema.microMark.id, id))
.returning();
markModel = updated[0];
} else {
const inserted = await db.insert(schema.microMark).values({
id: nanoid(),
data: data || {},
...rest,
uname: tokenUser.username,
uid: tokenUser.id,
puid: tokenUser.uid,
}).returning();
markModel = inserted[0];
}
ctx.body = markModel;
})
.addTo(app);
app
.route({
path: 'mark',
key: 'updateNode',
middleware: ['auth'],
})
.define(async (ctx) => {
const tokenUser = ctx.state.tokenUser;
const operate = ctx.query.operate || 'update';
const { id, node } = ctx.query.data || {};
const marks = await db.select().from(schema.microMark).where(eq(schema.microMark.id, id)).limit(1);
const markModel = marks[0];
if (!markModel) {
ctx.throw(404, 'mark not found');
}
if (markModel.uid !== tokenUser.id) {
ctx.throw(403, 'no permission');
}
// Update JSON node logic with Drizzle
const currentData = markModel.data as any || {};
const nodes = currentData.nodes || [];
const nodeIndex = nodes.findIndex((n: any) => n.id === node.id);
let updatedNodes;
if (operate === 'delete') {
updatedNodes = nodes.filter((n: any) => n.id !== node.id);
} else if (nodeIndex >= 0) {
updatedNodes = [...nodes];
updatedNodes[nodeIndex] = { ...nodes[nodeIndex], ...node };
} else {
updatedNodes = [...nodes, node];
}
const version = Number(markModel.version) + 1;
const updated = await db.update(schema.microMark)
.set({
data: { ...currentData, nodes: updatedNodes },
version,
updatedAt: new Date().toISOString(),
})
.where(eq(schema.microMark.id, id))
.returning();
ctx.body = updated[0];
})
.addTo(app);
app
.route({
path: 'mark',
key: 'updateNodes',
middleware: ['auth'],
})
.define(async (ctx) => {
const tokenUser = ctx.state.tokenUser;
const { id, nodeOperateList } = ctx.query.data || {};
const marks = await db.select().from(schema.microMark).where(eq(schema.microMark.id, id)).limit(1);
const markModel = marks[0];
if (!markModel) {
ctx.throw(404, 'mark not found');
}
if (markModel.uid !== tokenUser.id) {
ctx.throw(403, 'no permission');
}
if (!nodeOperateList || !Array.isArray(nodeOperateList) || nodeOperateList.length === 0) {
ctx.throw(400, 'nodeOperateList is required');
}
if (nodeOperateList.some((item: any) => !item.node)) {
ctx.throw(400, 'nodeOperateList node is required');
}
// Update multiple JSON nodes logic with Drizzle
const currentData = markModel.data as any || {};
let nodes = currentData.nodes || [];
for (const item of nodeOperateList) {
const { node, operate = 'update' } = item;
const nodeIndex = nodes.findIndex((n: any) => n.id === node.id);
if (operate === 'delete') {
nodes = nodes.filter((n: any) => n.id !== node.id);
} else if (nodeIndex >= 0) {
nodes[nodeIndex] = { ...nodes[nodeIndex], ...node };
} else {
nodes.push(node);
}
}
const version = Number(markModel.version) + 1;
const updated = await db.update(schema.microMark)
.set({
data: { ...currentData, nodes },
version,
updatedAt: new Date().toISOString(),
})
.where(eq(schema.microMark.id, id))
.returning();
ctx.body = updated[0];
})
.addTo(app);
app
.route({
path: 'mark',
key: 'delete',
middleware: ['auth'],
})
.define(async (ctx) => {
const tokenUser = ctx.state.tokenUser;
const { id } = ctx.query;
const marks = await db.select().from(schema.microMark).where(eq(schema.microMark.id, id)).limit(1);
const markModel = marks[0];
if (!markModel) {
ctx.throw(404, 'mark not found');
}
if (markModel.uid !== tokenUser.id) {
ctx.throw(403, 'no permission');
}
await db.delete(schema.microMark).where(eq(schema.microMark.id, id));
ctx.body = markModel;
})
.addTo(app);
app
.route({ path: 'mark', key: 'getMenu', description: '获取菜单', middleware: ['auth'] })
.define(async (ctx) => {
const tokenUser = ctx.state.tokenUser;
const [rows, totalResult] = await Promise.all([
db.select({
id: schema.microMark.id,
title: schema.microMark.title,
summary: schema.microMark.summary,
tags: schema.microMark.tags,
thumbnail: schema.microMark.thumbnail,
link: schema.microMark.link,
createdAt: schema.microMark.createdAt,
updatedAt: schema.microMark.updatedAt,
}).from(schema.microMark).where(eq(schema.microMark.uid, tokenUser.id)),
db.select({ count: count() }).from(schema.microMark).where(eq(schema.microMark.uid, tokenUser.id))
]);
ctx.body = {
list: rows,
total: totalResult[0]?.count || 0,
};
})
.addTo(app);