hydro-vue-orm
v0.0.1
Published
基于vue3 响应式orm库
Downloads
115
Readme
hydro-vue-orm
安装
npm install hydro-vue-orm
# 或
yarn add hydro-vue-orm什么是 hydro-vue-orm?
hydro-vue-orm 是基于vue3 响应式系统 实现的一套跨组件、跨页面 同步更新数据的方案
下面是一个基本的示例
<script setup>
import { Entity, Repository, Reactive } from 'hydro-vue-orm'
class UserModel {
id: string
name: string
age: number
}
/** 获取用户详情接口 */
const getUserDetail = (userId) => {
return fetch(`/api/users/${userId}`).then((res) => res.json()).then((data: UserModel) => {
return Repository(UserModel).insert(data) as Reactive<UserModel>
})
}
/** 获取用户列表接口 */
const getUserList = () => {
return fetch('/api/users').then((res) => res.json()).then((data: UserModel[]) => {
return data.map((item) => {
return Repository(UserModel).insert(item) as Reactive<UserModel>
})
})
}
const user1 = getUserDetail('userId1')
const user2 = getUserDetail('userId2')
const userList = getUserList()
/**
*
* 点击后, userList中所有id= userId1 的姓名 以及 user1 的姓名 会自动更新成 '用户1更新后的姓名'
* 不需要手动的去修改user1.name ===xxx, userList.forEach((user) => { user.id === userId1 && (user.name = '用户1更新后的姓名') })
*/
const onTapUpdateUserId1Name = () => {
Repository(UserModel).where({ id: 'userId1' }).update(user => {
user.name = '用户1更新后的姓名'
})
}
</script>
<template>
<div>用户1姓名: {{ user1.name }}</div>
<div>用户2姓名: {{ user2.name }}</div>
<div>用户列表: {{ userList.map((item) => item.name) }}</div>
</template>
核心原理
实现原理
当通过 Repository(UserModel).insert(data) 插入数据时,内部会执行以下步骤:
- 创建
UserModel的实例:new UserModel() - 将数据字段通过
Object.assign附加到实例上 - 使用
vue.reactive将实例转换为响应式对象 - 内部保持对该实例的弱引用
- 返回响应式对象
当通过 Repository(UserModel).where({ id: 'userId1' }) 进行操作时,框架会:
- 查找所有匹配条件的实例引用
- 对这些实例执行增删改查操作
- 由于使用了弱引用,当页面上的变量失效时,内部引用会自动释放
- 无需担心内存泄漏问题
类对象的优势
由于 insert 方法返回的是类的实例,我们可以在类上定义各种方法和属性,方便前端数据处理:
<script setup>
@Entity()
class UserModel {
id: number
name: string
get userInfo() {
return `用户姓名:${this.name},用户id:${this.id}`
}
}
const user1 = Repository(UserModel).insert({ id: 1, name: '用户1' })
</script>
<template>
<div>用户姓名: {{ user1.name }}</div>
<div>用户信息: {{ user1.userInfo }}</div>
</template>便捷数据处理
为了快速将接口数据转换为对应的响应式对象,我们提供了 @Entity 装饰器和 defineSchema 函数,简化数据映射过程:
<script setup>
import { Entity, defineSchema } from 'hydro-vue-orm'
@Entity()
class UserModel {
id: string
name: string
age: number
}
const data1 = [{ id: 1 },{ id: 2 }]
// data1转为了[UserModel, UserModel]
defineSchema([UserModel]).transform(data1)
const data2 = { book: user: { id: 1 } }
// data2自动转为了 { book: { user: UserModel } }
defineSchema({ book: { user: UserModel } }).transform(data2)
</script>装饰器
以下装饰器不会影响直接 new Class() 的行为,只有通过 Repository(UserModel).insert(data) 插入数据时才会生效:
@Entity()
装饰 class,用来配合 defineSchema 进行数据映射
示例代码
import { Entity } from 'hydro-vue-orm';
@Entity()
class UserModel {
id: string;
name: string;
age: number;
}@get
装饰属性,当读取实例的属性时触发
示例代码
import { Entity, get } from 'hydro-vue-orm';
@Entity()
class UserModel {
id: string;
name: string;
@get((value) => `${value} 岁`)
age: number;
}
// 使用
const user = Repository(UserModel).insert({ id: '1', name: '张三', age: 30 });
console.log(user.age); // 输出: 30 岁@set
装饰属性,当设置实例的属性时触发
示例代码
import { Entity, set } from 'hydro-vue-orm';
@Entity()
class UserModel {
id: string;
@set((value) => value || '未命名')
name: string;
age: number;
}
// 使用
const user = Repository(UserModel).insert({ id: '1', name: '', age: 30 });
console.log(user.name); // 输出: 未命名@types
装饰属性,基于 set + defineSchema,用来快捷地将属性转换为指定的类型
示例代码
import { Entity, types } from 'hydro-vue-orm';
@Entity()
class UserModel {
id: string;
name: string;
}
@Entity()
class PostModel {
id: string;
title: string;
@types(UserModel)
author: UserModel;
@types([UserModel])
contributors: UserModel[];
}
// 使用
const post = Repository(PostModel).insert({
id: '1',
title: '测试文章',
author: { id: '1', name: '张三' },
contributors: [
{ id: '1', name: '张三' },
{ id: '2', name: '李四' }
]
});
// post.author 和 post.contributors[0] 都是 UserModel 实例
console.log(post.author.name); // 输出: 张三
console.log(post.contributors[0].name); // 输出: 张三@cacheSync
装饰属性,慎用。在默认情况下,我们推荐使用 where().update() 来实现批量更新。但在某些特殊场景下,当你期望 id 相同时使用同一引用对象,你可以使用 @cacheSync 装饰器。
示例代码
import { Entity, cacheSync } from 'hydro-vue-orm';
@Entity()
class UserModel {
@cacheSync()
id: string;
name: string;
age: number;
}
// 使用
const user1 = Repository(UserModel).insert({ id: '1', name: '张三', age: 30 });
const user2 = Repository(UserModel).insert({ id: '1', name: '李四', age: 30 });
// user1 和 user2 是同一个实例
console.log(user1 === user2); // 输出: true
console.log(user1.name); // 输出: 李四, 后者覆盖前者
// 修改其中一个,另一个也会自动更新
user1.name = '王五';
console.log(user2.name); // 输出: 王五Repository 方法
Repository.insert(data)
插入新实例,返回响应式对象
参数
data: 要插入的数据对象
返回值
- 响应式实例对象
示例代码
const user = Repository(UserModel).insert({ id: '1', name: '张三', age: 30 });
console.log(user.name); // 输出: 张三Repository.where(conditions).update(callback)
更新匹配的实例
参数
conditions: 查询条件对象callback: 更新回调函数,接收匹配的实例作为参数
返回值
- 更新的实例数组
示例代码
// 更新指定条件的实例
Repository(UserModel).where({ id: '1' }).update(user => {
user.name = '更新后的姓名';
});
// 更新所有实例
Repository(UserModel).where({}).update(user => {
user.age = user.age + 1;
});Repository.where(conditions).delete()
删除匹配的实例
参数
conditions: 查询条件对象
返回值
- 删除的实例数组
示例代码
// 删除指定条件的实例
const deletedUsers = Repository(UserModel).where({ id: '1' }).delete();
console.log(deletedUsers.length); // 输出: 1Repository.where(conditions).find()
查找匹配的所有实例
参数
conditions: 查询条件对象
返回值
- 匹配的实例数组
示例代码
// 查找指定条件的实例
const users = Repository(UserModel).where({ age: 30 }).find();
console.log(users.length); // 输出: 匹配的用户数量Repository.where(conditions).findOne()
查找匹配的第一个实例
参数
conditions: 查询条件对象
返回值
- 匹配的实例或 undefined
示例代码
// 查找指定条件的第一个实例
const user = Repository(UserModel).where({ id: '1' }).findOne();
console.log(user?.name); // 输出: 找到的用户姓名Repository.all()
返回所有实例
返回值
- 所有实例的数组
示例代码
const allUsers = Repository(UserModel).all();
console.log(allUsers.length); // 输出: 所有用户数量Repository.clear()
清空所有实例
示例代码
Repository(UserModel).clear();
console.log(Repository(UserModel).all().length); // 输出: 0Repository.emitter
事件发射器,用于监听实例的插入、更新和删除事件
事件
insert: 当实例被插入时触发,参数为插入的实例update: 当实例被更新时触发,参数为更新的实例数组delete: 当实例被删除时触发,参数为删除的实例数组
示例代码
const repo = Repository(UserModel);
// 监听插入事件
repo.emitter.on('insert', user => {
console.log('用户已插入:', user);
});
// 监听更新事件
repo.emitter.on('update', users => {
console.log('用户已更新:', users);
});
// 监听删除事件
repo.emitter.on('delete', users => {
console.log('用户已删除:', users);
});defineSchema
定义数据映射模式,用来将接口数据转换为对应的响应式对象
参数
schema: 数据映射模式,可以是单个模型、模型数组或嵌套对象
返回值
- 包含
transform方法的对象
方法
transform(data): 将数据转换为对应的响应式对象data: 要转换的数据- 返回值: 转换后的响应式对象
示例代码
import { Entity, defineSchema } from 'hydro-vue-orm';
@Entity()
class UserModel {
id: string;
name: string;
age: number;
}
// 转换单个对象
const singleSchema = defineSchema(UserModel);
const user = singleSchema.transform({ id: '1', name: '张三', age: 30 });
console.log(user.name); // 输出: 张三
// 转换数组
const arraySchema = defineSchema([UserModel]);
const users = arraySchema.transform([
{ id: '1', name: '张三', age: 30 },
{ id: '2', name: '李四', age: 25 }
]);
console.log(users.length); // 输出: 2
// 转换嵌套对象
const nestedSchema = defineSchema({
user: UserModel,
users: [UserModel]
});
const result = nestedSchema.transform({
user: { id: '1', name: '张三', age: 30 },
users: [
{ id: '1', name: '张三', age: 30 },
{ id: '2', name: '李四', age: 25 }
]
});
console.log(result.user.name); // 输出: 张三
console.log(result.users.length); // 输出: 2
// 转换深层嵌套对象
const deepSchema = defineSchema({
book: {
author: UserModel,
contributors: [UserModel]
}
});
const deepResult = deepSchema.transform({
book: {
author: { id: '1', name: '张三', age: 30 },
contributors: [
{ id: '1', name: '张三', age: 30 },
{ id: '2', name: '李四', age: 25 }
]
}
});
console.log(deepResult.book.author.name); // 输出: 张三
console.log(deepResult.book.contributors.length); // 输出: 2浏览器兼容性
该库兼容所有支持 ES6+ 特性的现代浏览器。
TypeScript 支持
该库使用 TypeScript 编写,提供完整的类型支持。所有实体、仓库和查询构建器都有正确的类型定义。
许可证
MIT
