imean-cassandra-orm
v3.1.0
Published
cassandra orm
Readme
IMean Cassandra ORM
一个基于 Zod 的 Cassandra ORM,提供类型安全的 schema 定义和数据库操作。
特性
- 🎯 类型安全: 基于 Zod 的 schema 验证和 TypeScript 类型推断,确保入库和出库的数据类型安全。
- 🔧 自动 CQL 生成: 自动生成 Cassandra CQL 语句,无需手写。
- 📊 完整 CRUD: 支持插入、查询、更新、删除操作。
- 🚀 批量操作: 支持批量插入,提升性能。
- 🎨 简洁 API: 简单易用的 API 设计,通过 Client 统一管理模型。
- 🔄 Schema 同步: 自动创建和同步 keyspace 和表结构。
- ⚙️ Keyspace 配置: 支持自定义复制策略和配置。
- 🤖 自动序列化: 自动处理复杂类型(如 JSON 对象、数组)的序列化和反序列化。
- 📊 ClickHouse 双写: 可选的 ClickHouse 双写功能,支持实时数据分析和自动表结构同步。
安装
npm install imean-cassandra-orm快速开始
1. 定义 Schema
使用 TableSchema 和 zod 来定义你的表结构。ORM 会根据你的定义自动推断类型和生成数据库表。
import { z } from "zod";
import { TableSchema } from "imean-cassandra-orm";
// 定义用户表 schema
const userSchema = new TableSchema({
fields: {
user_id: z.string(),
email: z.string().email(),
name: z.string(),
age: z.number().int().positive(),
is_active: z.boolean(),
metadata: z.record(z.any()), // 可以是任意复杂的对象
created_at: z.date(),
},
partitionKey: ["user_id"],
tableName: "users",
keyspace: "my_app_keyspace",
});
// 定义帖子表 schema(带聚类键)
const postSchema = new TableSchema({
fields: {
user_id: z.string(),
post_id: z.string(),
title: z.string(),
content: z.string(),
tags: z.array(z.string()), // 数组类型
published_at: z.date(),
},
partitionKey: ["user_id"],
clusteringKey: { post_id: "desc" }, // 按 post_id 降序
tableName: "posts",
keyspace: "my_app_keyspace",
});2. 创建 Client 和模型
Client 是所有操作的入口。你需要先创建一个 Client 实例,然后用它来创建 Model 实例。
import { Client } from "imean-cassandra-orm";
// 1. 创建 Client 实例
const client = new Client({
contactPoints: ["localhost"],
localDataCenter: "datacenter1",
});
// 2. 连接到 Cassandra
await client.connect();
// 3. (可选) 删除旧的 keyspace 以进行全新测试
await client.dropKeyspace("my_app_keyspace");
// 4. 通过 Client 创建模型实例
const userModel = client.createModel(userSchema);
const postModel = client.createModel(postSchema);
// 5. 同步所有模型的 Schema
// 这会确保 keyspace 和所有相关的表都已创建
// 如果启用了双写,也会同步 ClickHouse 表结构
await client.syncSchema();client.syncSchema() 会自动处理所有已创建模型的 schema 同步,你不再需要为每个模型单独调用 syncSchema()。
3. 基本操作
模型实例提供了完整的 CRUD API。
// 插入数据 (自动序列化 metadata 对象)
const userData = {
user_id: "user1",
email: "[email protected]",
name: "张三",
age: 25,
is_active: true,
metadata: { score: 95.5, level: 3, tags: ["vip"] },
created_at: new Date(),
};
await userModel.insert(userData);
// 查询数据 (自动反序列化 metadata)
const foundUser = await userModel.findOne({ user_id: "user1" });
console.log(foundUser?.metadata); // { score: 95.5, level: 3, tags: ["vip"] }
// 更新数据
await userModel.update(
{ user_id: "user1" },
{ name: "李四", age: 26 }
);
// 删除数据
await userModel.delete({ user_id: "user1" });4. 批量操作
// 批量插入
const usersData = [
{
user_id: "user2",
email: "[email protected]",
name: "王五",
age: 30,
is_active: true,
metadata: { score: 88.0 },
created_at: new Date(),
},
{
user_id: "user3",
email: "[email protected]",
name: "赵六",
age: 28,
is_active: false,
metadata: { score: 79.2 },
created_at: new Date(),
},
];
await userModel.batchInsert(usersData);5. 使用聚类键
当你的 schema 定义了 clusteringKey 时,你可以在查询、更新和删除操作中指定它。
// 插入带聚类键的数据
const postData = {
user_id: "user1",
post_id: "post1",
title: "我的第一篇帖子",
content: "这是内容...",
tags: ["技术", "编程"],
published_at: new Date(),
};
await postModel.insert(postData);
// 查询特定帖子
const post = await postModel.findOne(
{ user_id: "user1" },
{ post_id: "post1" } // 指定聚类键
);
// 更新特定帖子
await postModel.update(
{ user_id: "user1" },
{ title: "更新后的标题" },
{ post_id: "post1" } // 指定聚类键
);
// 删除特定帖子
await postModel.delete(
{ user_id: "user1" },
{ post_id: "post1" } // 指定聚类键
);6. 类型安全与校验
ORM 会在数据返回时使用 Zod schema 进行校验,确保你得到的数据是类型安全的。
// 从数据库返回的数据
const userFromDb = await userModel.findOne({ user_id: "user1" });
// userFromDb 的类型是根据 userSchema 推断出来的,具有完整的类型提示
if (userFromDb) {
console.log(userFromDb.name.toUpperCase());
}
// 如果数据库中的数据不符合 schema(例如,手动修改了数据库),
// 在查询时会抛出 ZodError,防止脏数据进入你的应用。ClickHouse 双写功能
框架支持可选的 ClickHouse 双写功能,可以将 Cassandra 的操作同步到 ClickHouse 中用于分析查询。
配置双写功能
import { Client } from "imean-cassandra-orm";
const client = new Client({
contactPoints: ["localhost"],
localDataCenter: "datacenter1",
keyspace: "my_keyspace",
dualWrite: {
enabled: true,
clickhouse: {
host: "localhost",
port: 8123,
username: "default",
password: "",
database: "analytics",
},
operations: {
insert: true,
update: true,
delete: true,
},
errorHandling: "log", // 'ignore' | 'log' | 'throw'
debug: true,
},
});使用双写功能
启用双写后,所有的插入、更新、删除操作都会自动同步到 ClickHouse:
// 连接数据库
await client.connect();
// 同步 schema(会自动同步到 ClickHouse)
await client.syncSchema();
// 创建模型
const UserModel = client.createModel(userSchema);
// 插入数据(会自动双写到 ClickHouse)
await UserModel.insert({
user_id: "user1",
email: "[email protected]",
name: "张三",
age: 25,
is_active: true,
created_at: new Date(),
});
// 批量插入(会自动双写到 ClickHouse)
await UserModel.batchInsert([...]);
// 更新数据(会自动双写到 ClickHouse)
await UserModel.update({ user_id: "user1" }, { age: 26 });
// 删除数据(会自动双写到 ClickHouse)
await UserModel.delete({ user_id: "user1" });检查双写状态
if (client.isDualWriteEnabled()) {
console.log("双写功能已启用");
}更多详细信息请参考 双写功能文档。
API 参考
Client
new Client(options: cassandra.ClientOptions)
创建一个新的 Client 实例。options 与 cassandra-driver 的 ClientOptions 相同。
client.connect(): Promise<void>
连接到 Cassandra 集群。
client.createModel(schema: TableSchema): Model
根据 TableSchema 创建一个 Model 实例。
client.syncSchema(): Promise<void>
同步所有通过 createModel 创建的模型的 schema。
client.dropKeyspace(keyspace: string): Promise<void>
删除一个 keyspace。
Model
model.insert(data: T): Promise<void>
插入一条数据。
model.batchInsert(data: T[]): Promise<void>
批量插入多条数据。
model.find(partitionKey: PK): Promise<T[]>
根据分区键查询多条数据。
model.findOne(partitionKey: PK, clusteringKey?: CK): Promise<T | null>
根据分区键和(可选的)聚类键查询单条数据。
model.update(partitionKey: PK, data: Partial<T>, clusteringKey?: CK): Promise<void>
更新一条数据。
model.delete(partitionKey: PK, clusteringKey?: CK): Promise<void>
删除一条数据。
贡献者:imean License: MIT
