Refactor app management to use Drizzle ORM

- Replaced Sequelize models with Drizzle ORM for app and app list management.
- Updated routes in app-manager to utilize new database queries.
- Removed obsolete Sequelize model files for app, app list, and app domain.
- Introduced new helper functions for app and app domain management.
- Enhanced user app management with improved file handling and user migration.
- Adjusted public API routes to align with new database structure.
- Implemented caching mechanisms for domain management.
This commit is contained in:
2026-02-07 01:26:16 +08:00
parent d62a75842f
commit 7dfa96d165
40 changed files with 1066 additions and 1171 deletions

View File

@@ -1,12 +1,14 @@
import { App, CustomError } from '@kevisual/router';
import { AppModel, AppListModel } from './module/index.ts';
import { app, redis } from '@/app.ts';
import { App as AppType, AppList, AppData, AppHelper } from './module/app-drizzle.ts';
import { app, redis, db, schema } from '@/app.ts';
import { uniqBy } from 'es-toolkit';
import { getUidByUsername, prefixFix } from './util.ts';
import { deleteFiles, getMinioListAndSetToAppList } from '../file/index.ts';
import { setExpire } from './revoke.ts';
import { User } from '@/models/user.ts';
import { callDetectAppVersion } from './export.ts';
import { eq, and, desc } from 'drizzle-orm';
import { randomUUID } from 'crypto';
app
.route({
path: 'app',
@@ -20,14 +22,13 @@ app
if (!data.key) {
throw new CustomError('key is required');
}
const list = await AppListModel.findAll({
order: [['updatedAt', 'DESC']],
where: {
uid: tokenUser.id,
key: data.key,
},
logging: false,
});
const list = await db.select()
.from(schema.kvAppList)
.where(and(
eq(schema.kvAppList.uid, tokenUser.id),
eq(schema.kvAppList.key, data.key)
))
.orderBy(desc(schema.kvAppList.updatedAt));
ctx.body = list.map((item) => prefixFix(item, tokenUser.username));
return ctx;
})
@@ -48,33 +49,35 @@ app
if (!id && (!key || !version)) {
throw new CustomError('id is required');
}
let appListModel: AppListModel;
let appListModel: AppList | undefined;
if (id) {
appListModel = await AppListModel.findByPk(id);
const apps = await db.select().from(schema.kvAppList).where(eq(schema.kvAppList.id, id)).limit(1);
appListModel = apps[0];
} else if (key && version) {
appListModel = await AppListModel.findOne({
where: {
key,
version,
uid: tokenUser.id,
},
});
const apps = await db.select().from(schema.kvAppList).where(and(
eq(schema.kvAppList.key, key),
eq(schema.kvAppList.version, version),
eq(schema.kvAppList.uid, tokenUser.id)
)).limit(1);
appListModel = apps[0];
}
if (!appListModel && create) {
appListModel = await AppListModel.create({
const newApps = await db.insert(schema.kvAppList).values({
id: randomUUID(),
key,
version,
uid: tokenUser.id,
data: {},
});
const appModel = await AppModel.findOne({
where: {
key,
uid: tokenUser.id,
},
});
}).returning();
appListModel = newApps[0];
const appModels = await db.select().from(schema.kvApp).where(and(
eq(schema.kvApp.key, key),
eq(schema.kvApp.uid, tokenUser.id)
)).limit(1);
const appModel = appModels[0];
if (!appModel) {
await AppModel.create({
await db.insert(schema.kvApp).values({
id: randomUUID(),
key,
uid: tokenUser.id,
user: tokenUser.username,
@@ -88,13 +91,12 @@ app
if (res.code !== 200) {
ctx.throw(res.message || 'detect version list error');
}
appListModel = await AppListModel.findOne({
where: {
key,
version,
uid: tokenUser.id,
},
});
const apps2 = await db.select().from(schema.kvAppList).where(and(
eq(schema.kvAppList.key, key),
eq(schema.kvAppList.version, version),
eq(schema.kvAppList.uid, tokenUser.id)
)).limit(1);
appListModel = apps2[0];
}
if (!appListModel) {
ctx.throw('app not found');
@@ -115,10 +117,16 @@ app
const tokenUser = ctx.state.tokenUser;
const { data, id, ...rest } = ctx.query.data;
if (id) {
const app = await AppListModel.findByPk(id);
const apps = await db.select().from(schema.kvAppList).where(eq(schema.kvAppList.id, id)).limit(1);
const app = apps[0];
if (app) {
const newData = { ...app.data, ...data };
const newApp = await app.update({ data: newData, ...rest });
const appData = app.data as AppData;
const newData = { ...appData, ...data };
const updateResult = await db.update(schema.kvAppList)
.set({ data: newData, ...rest, updatedAt: new Date().toISOString() })
.where(eq(schema.kvAppList.id, id))
.returning();
const newApp = updateResult[0];
ctx.body = newApp;
setExpire(newApp.id, 'test');
} else {
@@ -130,8 +138,8 @@ app
if (!rest.key) {
throw new CustomError('key is required');
}
const app = await AppListModel.create({ data, ...rest, uid: tokenUser.id });
ctx.body = app;
const newApps = await db.insert(schema.kvAppList).values({ id: randomUUID(), data, ...rest, uid: tokenUser.id }).returning();
ctx.body = newApps[0];
return ctx;
})
.addTo(app);
@@ -149,24 +157,28 @@ app
if (!id) {
throw new CustomError('id is required');
}
const app = await AppListModel.findByPk(id);
const apps = await db.select().from(schema.kvAppList).where(eq(schema.kvAppList.id, id)).limit(1);
const app = apps[0];
if (!app) {
throw new CustomError('app not found');
}
const am = await AppModel.findOne({ where: { key: app.key, uid: app.uid } });
const ams = await db.select().from(schema.kvApp).where(and(
eq(schema.kvApp.key, app.key),
eq(schema.kvApp.uid, app.uid)
)).limit(1);
const am = ams[0];
if (!am) {
throw new CustomError('app not found');
}
if (am.version === app.version) {
throw new CustomError('app is published');
}
const files = app.data.files || [];
const appData = app.data as AppData;
const files = appData.files || [];
if (deleteFile && files.length > 0) {
await deleteFiles(files.map((item) => item.path));
}
await app.destroy({
force: true,
});
await db.delete(schema.kvAppList).where(eq(schema.kvAppList.id, id));
ctx.body = 'success';
return ctx;
})
@@ -205,11 +217,16 @@ app
throw new CustomError('user not found');
}
}
let am = await AppModel.findOne({ where: { key: appKey, uid } });
const ams = await db.select().from(schema.kvApp).where(and(
eq(schema.kvApp.key, appKey),
eq(schema.kvApp.uid, uid)
)).limit(1);
let am = ams[0];
let appIsNew = false;
if (!am) {
appIsNew = true;
am = await AppModel.create({
const newAms = await db.insert(schema.kvApp).values({
id: randomUUID(),
user: userPrefix,
key: appKey,
uid,
@@ -220,24 +237,40 @@ app
data: {
files: files || [],
},
});
}).returning();
am = newAms[0];
}
let app = await AppListModel.findOne({ where: { version: version, key: appKey, uid: uid } });
const apps = await db.select().from(schema.kvAppList).where(and(
eq(schema.kvAppList.version, version),
eq(schema.kvAppList.key, appKey),
eq(schema.kvAppList.uid, uid)
)).limit(1);
let app = apps[0];
if (!app) {
app = await AppListModel.create({
const newApps = await db.insert(schema.kvAppList).values({
id: randomUUID(),
key: appKey,
version,
uid: uid,
data: {
files: [],
},
});
}).returning();
app = newApps[0];
}
const dataFiles = app.data.files || [];
const appData = app.data as AppData;
const dataFiles = appData.files || [];
const newFiles = uniqBy([...dataFiles, ...files], (item) => item.name);
const res = await app.update({ data: { ...app.data, files: newFiles } });
const updateResult = await db.update(schema.kvAppList)
.set({ data: { ...appData, files: newFiles }, updatedAt: new Date().toISOString() })
.where(eq(schema.kvAppList.id, app.id))
.returning();
const res = updateResult[0];
if (version === am.version && !appIsNew) {
await am.update({ data: { ...am.data, files: newFiles } });
const amData = am.data as AppData;
await db.update(schema.kvApp)
.set({ data: { ...amData, files: newFiles }, updatedAt: new Date().toISOString() })
.where(eq(schema.kvApp.id, am.id));
}
setExpire(app.id, 'test');
ctx.body = prefixFix(res, userPrefix);
@@ -263,9 +296,10 @@ app
}
const uid = await getUidByUsername(app, ctx, username);
let appList: AppListModel | null = null;
let appList: AppList | undefined = undefined;
if (id) {
appList = await AppListModel.findByPk(id);
const appLists = await db.select().from(schema.kvAppList).where(eq(schema.kvAppList.id, id)).limit(1);
appList = appLists[0];
if (appList?.uid !== uid) {
ctx.throw('no permission');
}
@@ -274,7 +308,12 @@ app
if (!version) {
ctx.throw('version is required');
}
appList = await AppListModel.findOne({ where: { key: appKey, version, uid } });
const appLists = await db.select().from(schema.kvAppList).where(and(
eq(schema.kvAppList.key, appKey),
eq(schema.kvAppList.version, version),
eq(schema.kvAppList.uid, uid)
)).limit(1);
appList = appLists[0];
}
if (!appList) {
ctx.throw('app 未发现');
@@ -287,18 +326,27 @@ app
if (res.code !== 200) {
ctx.throw(res.message || '检测版本列表失败');
}
appList = await AppListModel.findByPk(appList.id);
const appLists2 = await db.select().from(schema.kvAppList).where(eq(schema.kvAppList.id, appList.id)).limit(1);
appList = appLists2[0];
}
if (!appList) {
ctx.throw('app 未发现');
}
const files = appList.data.files || [];
const am = await AppModel.findOne({ where: { key: appList.key, uid: uid } });
const appListData = appList.data as AppData;
const files = appListData.files || [];
const ams = await db.select().from(schema.kvApp).where(and(
eq(schema.kvApp.key, appList.key),
eq(schema.kvApp.uid, uid)
)).limit(1);
const am = ams[0];
if (!am) {
ctx.throw('app 未发现');
}
await am.update({ data: { ...am.data, files }, version: appList.version });
const amData = am.data as AppData;
await db.update(schema.kvApp)
.set({ data: { ...amData, files }, version: appList.version, updatedAt: new Date().toISOString() })
.where(eq(schema.kvApp.id, am.id));
setExpire(appList.key, am.user);
ctx.body = {
key: appList.key,
@@ -317,11 +365,16 @@ app
})
.define(async (ctx) => {
const { user, key, id } = ctx.query.data;
let app;
let app: AppType | undefined;
if (id) {
app = await AppModel.findByPk(id);
const apps = await db.select().from(schema.kvApp).where(eq(schema.kvApp.id, id)).limit(1);
app = apps[0];
} else if (user && key) {
app = await AppModel.findOne({ where: { user, key } });
const apps = await db.select().from(schema.kvApp).where(and(
eq(schema.kvApp.user, user),
eq(schema.kvApp.key, key)
)).limit(1);
app = apps[0];
} else {
throw new CustomError('user or key is required');
}
@@ -364,16 +417,23 @@ app
throw new CustomError('appKey and version are required');
}
const uid = await getUidByUsername(app, ctx, username);
let appList = await AppListModel.findOne({ where: { key: appKey, version, uid } });
const appLists = await db.select().from(schema.kvAppList).where(and(
eq(schema.kvAppList.key, appKey),
eq(schema.kvAppList.version, version),
eq(schema.kvAppList.uid, uid)
)).limit(1);
let appList = appLists[0];
if (!appList) {
appList = await AppListModel.create({
const newAppLists = await db.insert(schema.kvAppList).values({
id: randomUUID(),
key: appKey,
version,
uid,
data: {
files: [],
},
});
}).returning();
appList = newAppLists[0];
}
const checkUsername = username || tokenUser.username;
const files = await getMinioListAndSetToAppList({ username: checkUsername, appKey, version });
@@ -383,7 +443,8 @@ app
path: item.name,
};
});
let appListFiles = appList.data?.files || [];
const appListData = appList.data as AppData;
let appListFiles = appListData?.files || [];
const needAddFiles = newFiles.map((item) => {
const findFile = appListFiles.find((appListFile) => appListFile.name === item.name);
if (findFile && findFile.name === item.name) {
@@ -391,11 +452,20 @@ app
}
return item;
});
await appList.update({ data: { files: needAddFiles } });
const updateResult = await db.update(schema.kvAppList)
.set({ data: { files: needAddFiles }, updatedAt: new Date().toISOString() })
.where(eq(schema.kvAppList.id, appList.id))
.returning();
appList = updateResult[0];
setExpire(appList.id, 'test');
let am = await AppModel.findOne({ where: { key: appKey, uid } });
const ams = await db.select().from(schema.kvApp).where(and(
eq(schema.kvApp.key, appKey),
eq(schema.kvApp.uid, uid)
)).limit(1);
let am = ams[0];
if (!am) {
am = await AppModel.create({
const newAms = await db.insert(schema.kvApp).values({
id: randomUUID(),
title: appKey,
key: appKey,
version: version || '0.0.1',
@@ -403,11 +473,19 @@ app
uid,
data: { files: needAddFiles },
proxy: appKey.includes('center') ? false : true,
});
}).returning();
am = newAms[0];
} else {
const appModel = await AppModel.findOne({ where: { key: appKey, version, uid } });
const appModels = await db.select().from(schema.kvApp).where(and(
eq(schema.kvApp.key, appKey),
eq(schema.kvApp.version, version),
eq(schema.kvApp.uid, uid)
)).limit(1);
const appModel = appModels[0];
if (appModel) {
await appModel.update({ data: { files: needAddFiles } });
await db.update(schema.kvApp)
.set({ data: { files: needAddFiles }, updatedAt: new Date().toISOString() })
.where(eq(schema.kvApp.id, appModel.id));
setExpire(appModel.key, appModel.user);
}
}