如何用pg-promise将SELECT查询结果自动映射到预定义Dog类实例
嘿,这个问题我太懂了!每次手动遍历映射确实烦得很,pg-promise其实有现成的办法帮你搞定自动映射,不用重复造轮子。下面给你两种实用方案:
方案一:封装通用映射函数(最推荐,灵活复用)
首先给你的Dog类加个能接收plain object的构造函数(如果还没加的话):
class Dog { id: number; legs: number; // 接收数据库返回的普通对象,直接赋值属性 constructor(data: { id: number; legs: number }) { this.id = data.id; this.legs = data.legs; } // 比如你后续加的类方法,比如bark() bark(): void { console.log(`Dog ${this.id} woofs!`); } }
然后写一个通用的映射函数,把数据库返回的普通对象转换成指定类的实例:
// 通用工具函数:接收类构造器,返回一个转换函数 const mapToClass = <T>(cls: new (data: any) => T) => (data: any): T => new cls(data);
接下来修改你的getDogs方法,只用一行就能完成自动映射:
getDogs(): Promise<Dog[]> { return this.db.any('SELECT id, legs FROM Dog') .then(dogObjects => dogObjects.map(mapToClass(Dog))); }
这样调用await Database.getDogs()时,拿到的就是真正的Dog实例数组,不仅类型正确,还能直接调用类里的方法(比如上面的bark())。而且这个工具函数可以复用给任何其他类,比如你有Cat类,直接用mapToClass(Cat)就行,完全不用重复写遍历逻辑!
方案二:全局结果转换(适合全项目统一规则)
如果你想让所有查询Dog表的结果自动转成Dog实例,可以在初始化pg-promise的时候配置全局的结果处理钩子:
import pgPromise from 'pg-promise'; // 初始化pg-promise时添加receive钩子 const pgp = pgPromise({ receive(data, result, _err) { // 检查当前查询的结果是否来自Dog表(通过字段的tableName判断) const isDogTable = result.fields.some(field => field.tableName === 'Dog'); if (isDogTable) { data.rows = data.rows.map(row => new Dog(row)); } } }); // 然后创建数据库实例 const db = pgp('your-db-connection-string');
这种方式一劳永逸,所有查Dog表的SQL都会自动把结果转成Dog实例,但要注意:如果你的查询是多表关联,可能会误判,所以适合单一表查询的场景。
小提醒
如果数据库列名和类属性名不一致(比如数据库是leg_count,类里是legs),只要在构造函数里做个转换就行:
constructor(data: { id: number; leg_count: number }) { this.id = data.id; this.legs = data.leg_count; // 转换列名到属性名 }
这样不管列名怎么变,都能轻松适配~
内容的提问来源于stack exchange,提问作者Mirt Hlaj
相关产品推荐
相关产品推荐

