Compare commits

..
3 Commits
Author SHA1 Message Date
wc24 6383aade98 fix(crud): 响应统一剥掉 mongoose 版本键 __v
filterHidden 出口加剥 __v(连同 hidden 字段),list/get/add/edit 全覆盖。
前端无用的 __v 不再下发。
2026-06-30 14:09:44 +08:00
wc24 d12877f846 fix(crud): add/edit 返回普通对象(toObject/lean),不再抖出 mongoose Document 内部
add 用 create 返回 Document、edit 用 findByIdAndUpdate 返回 Document,下游 processResItem
的 {...item} 会把 $__/_doc/$isNew 等内部属性展开、真数据埋进 _doc。改:add 转 toObject、
edit 加 .lean()(与 list/get 一致)。响应回归干净 POJO。
2026-06-30 14:06:40 +08:00
wc24 c264ec6673 feat!: 去掉 json 类型(object 取代) + 版本统一 0.7.0
- object 字段已能声明式表达嵌套结构,freeform 的 json 类型不再需要:
  删 ShrimpFieldTypes.Json + defaultTypeHandlers[Json](reqFilter/resFilter)。
- 源码无任何 type:json 使用,安全移除。
- 前后端版本自此统一:一起推的版本用相同版本号,本批 = 0.7.0。
2026-06-29 22:25:58 +08:00
4 changed files with 6 additions and 25 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "shrimp-server", "name": "shrimp-server",
"version": "0.6.11", "version": "0.7.2",
"description": "Shrimp 框架后端 — 声明式字段驱动的 Node.js 管理后台框架(Express + Mongoose + JWT)", "description": "Shrimp 框架后端 — 声明式字段驱动的 Node.js 管理后台框架(Express + Mongoose + JWT)",
"main": "dist/main/index.js", "main": "dist/main/index.js",
"types": "dist/main/index.d.ts", "types": "dist/main/index.d.ts",
-1
View File
@@ -235,7 +235,6 @@ export const ShrimpFieldTypes = {
Textarea: "textarea" as ShrimpFieldType, Textarea: "textarea" as ShrimpFieldType,
Password: "password" as ShrimpFieldType, Password: "password" as ShrimpFieldType,
Relation: "relation" as ShrimpFieldType, Relation: "relation" as ShrimpFieldType,
Json: "json" as ShrimpFieldType,
Tab: "tab" as ShrimpFieldType, Tab: "tab" as ShrimpFieldType,
Object: "object" as ShrimpFieldType, Object: "object" as ShrimpFieldType,
Array: "array" as ShrimpFieldType, Array: "array" as ShrimpFieldType,
+2 -21
View File
@@ -27,26 +27,6 @@ export const defaultTypeHandlers: Record<string, IFieldTypeHandler> = {
[ShrimpFieldTypes.Boolean]: { [ShrimpFieldTypes.Boolean]: {
defaultValue: false, defaultValue: false,
}, },
[ShrimpFieldTypes.Json]: {
reqFilter: (value) => {
if (value == null || value === "") return undefined
if (typeof value === "string") {
try {
return JSON.parse(value)
} catch {
throw new ShrimpError({ t: 'shrimp.invalidJson' })
}
}
return value
},
resFilter: (value) => {
if (value == null) return value
if (typeof value === "object") {
return JSON.stringify(value)
}
return value
},
},
[ShrimpFieldTypes.Tab]: { [ShrimpFieldTypes.Tab]: {
// tab 是结构化字段:库里/响应/编辑全程是对象,只在"给人看"的边界(import/export/label)走字符串。 // tab 是结构化字段:库里/响应/编辑全程是对象,只在"给人看"的边界(import/export/label)走字符串。
reqFilter: (value, field) => { reqFilter: (value, field) => {
@@ -288,7 +268,8 @@ export class ShrimpTableModule<T, P extends ITableCrudProto<T> = ITableCrudProto
} }
private filterHidden(item: any): any { private filterHidden(item: any): any {
return this.excludeKeys(item, this.fields.filter(f => f.hidden).map(f => f.key)) // __v 是 mongoose 版本键,前端无用,统一剥掉(连同 hidden 字段)
return this.excludeKeys(item, ["__v", ...this.fields.filter(f => f.hidden).map(f => f.key)])
} }
private buildQuery(query?: IPageQuery & any): IShrimpQuery { private buildQuery(query?: IPageQuery & any): IShrimpQuery {
+3 -2
View File
@@ -107,10 +107,11 @@ export class MongoShrimpCrud<T> implements ShrimpCrud<T> {
return await this.model.findById(id).lean() as T | null return await this.model.findById(id).lean() as T | null
} }
async add(item: Omit<T, '_id'>): Promise<T> { async add(item: Omit<T, '_id'>): Promise<T> {
return await this.model.create(item) const doc = await this.model.create(item)
return doc.toObject() as T // 转普通对象,否则下游 {...item} 展开的是 mongoose Document 内部($__/_doc/$isNew)
} }
async edit(id: string, item: Partial<T>): Promise<T | null> { async edit(id: string, item: Partial<T>): Promise<T | null> {
return await this.model.findByIdAndUpdate(id, item, { new: true }) return await this.model.findByIdAndUpdate(id, item, { new: true }).lean() as T | null
} }
async delete(id: string): Promise<boolean> { async delete(id: string): Promise<boolean> {
const result = await this.model.findByIdAndDelete(id) const result = await this.model.findByIdAndDelete(id)