tablestore-odm
Version:
A simple and powerful Object Document Mapper (ODM) for Aliyun Tablestore, built with TypeScript and Zod.
202 lines (151 loc) • 5.19 kB
Markdown
# Tablestore ODM
**Tablestore ODM** 是一个基于 [阿里云表格存储 (Tablestore)](https://www.aliyun.com/product/ots) 的对象文档映射 (ODM) 库,旨在简化与 Tablestore 的交互,提供更直观、类型安全的数据操作体验。
## 特性
- **Schema 定义:** 使用 Zod 进行数据模型定义和验证,确保数据类型安全。
- **模型抽象:** 将 Tablestore 表映射为 JavaScript 类,提供 CRUD 方法。
- **查询构建器:** 提供链式调用的查询构建器,支持范围查询和多元索引查询。
- **范围查询 (Range Query):** 使用 `startWith` 和 `endAt` 指定范围,支持正向和反向查询,可设置 `limit` 限制返回数量,使用 `filter` 进行服务端过滤。
- **多元索引查询 (Search Query):** 支持全文检索、精确匹配、前缀匹配、范围查询、通配符查询、地理位置查询等多种查询类型,并支持排序、分页和结果折叠。
- **类型安全:** 充分利用 TypeScript 的类型推断,减少运行时错误。
- **连接管理:** 统一管理 Tablestore 客户端连接。
- **灵活配置:** 支持自定义配置,并允许透传 Tablestore SDK 的其他选项。
- **批量操作:** 支持 `insertMany` 和 `deleteMany` 进行批量插入和删除操作。
- **GSI 支持:** 支持全局二级索引 (GSI) 的查询。
- **字段类型转换:** 自动处理 JavaScript 类型与 Tablestore 类型的转换,例如 `number` 到 `Long`,`Date` 到时间戳等。
## 安装
```bash
npm install tablestore-odm
```
## 使用
### 快速开始
1. 定义 Schema:
```typescript
import { z } from "zod";
import { createSchema } from "tablestore-odm";
const UserSchema = z.object({
id: z.string(),
name: z.string(),
age: z.number().int().positive(),
email: z.string().email().optional(),
});
const userSchema = createSchema(UserSchema, {
primaryKeys: ["id"],
timestamps: true, // 自动管理 createdAt 和 updatedAt 字段
});
```
2. 创建 Model:
```typescript
import { Connection, createModel } from "tablestore-odm";
const connection = new Connection({
endpoint: "your_endpoint",
accessKeyId: "your_access_key_id",
secretAccessKey: "your_secret_access_key",
instancename: "your_instance_name",
});
const UserModel = createModel(
"User",
userSchema,
"your_user_table_name",
connection
);
```
```typescript
async function main() {
// 创建用户
const [createErr, createdUser] = await UserModel.create({
id: "user123",
name: "Alice",
age: 30,
email: "<alice@example.com>",
});
if (createErr) {
console.error("创建用户失败:", createErr);
return;
}
console.log("创建用户成功:", createdUser);
// 查询用户
const [findErr, foundUser] = await UserModel.findById({ id: "user123" });
if (findErr) {
console.error("查询用户失败:", findErr);
return;
}
if (foundUser) {
console.log("查询用户成功:", foundUser);
// 更新用户
const [updateErr] = await UserModel.updateById(
{ id: "user123" },
{ age: 31 }
);
if (updateErr) {
console.error("更新用户失败:", updateErr);
return;
}
console.log("更新用户成功");
// 删除用户
const [deleteErr] = await UserModel.deleteById({ id: "user123" });
if (deleteErr) {
console.error("删除用户失败:", deleteErr);
return;
}
console.log("删除用户成功");
} else {
console.log("未找到用户");
}
}
main();
```
- 范围查询
``` typescript
// 查询年龄在 20 到 30 岁之间的用户
const [err, result] = await UserModel.range()
.startWith({ age: 20 })
.endAt({ age: 30 })
.filter((q) => q.greaterThanOrEqual("age", 20).lessThanOrEqual("age", 30)) // 使用 filter 进行服务端过滤
.exec();
if (err) {
console.error("范围查询失败:", err);
} else {
console.log("范围查询结果:", result?.rows);
}
```
- 多元索引查询
``` typescript
// 假设有一个名为 "user_search_index" 的多元索引
const [err, result] = await UserModel.search("user_search_index")
.filter((q) => q.match("name", "Alice")) // 匹配名字包含 "Alice" 的用户
.limit(10)
.exec();
if (err) {
console.error("多元索引查询失败:", err);
} else {
console.log("多元索引查询结果:", result?.rows);
console.log("总匹配数:", result?.totalCount);
}
// 精确匹配
UserModel.search("user_search_index").filter(q => q.term("city", "Beijing")).exec();
```
### 批量操作
``` typescript
// 批量插入
const [insertErr, insertedKeys] = await UserModel.insertMany([
{ id: "user4", name: "David", age: 25 },
{ id: "user5", name: "Eve", age: 28 },
]);
if (insertErr) {
console.error("批量插入失败:", insertErr);
} else {
console.log("批量插入成功,插入的主键:", insertedKeys);
}
// 批量删除
const [deleteErr, deletedKeys] = await UserModel.deleteMany([
{ id: "user4" },
{ id: "user5" },
]);
if (deleteErr) {
console.error("批量删除失败:", deleteErr);
} else {
console.log("批量删除成功,删除的主键:", deletedKeys);
}
```
# 许可证
MIT 许可证