UNPKG

imean-cassandra-orm

Version:

cassandra orm

348 lines (272 loc) 9.54 kB
# Cassandra ORM 一个简单易用的 Cassandra ORM 库,提供类型安全的 API ## 安装 ```bash npm install imean-cassandra-orm ``` ## 使用示例 ```typescript import { Client as CassandraClient, auth } from "cassandra-driver"; import { Client, Field, uuid, type Infer } from "imean-cassandra-orm"; // 创建原始 Cassandra 客户端 const cassandraClient = new CassandraClient({ contactPoints: ["localhost"], localDataCenter: "datacenter1", authProvider: new auth.PlainTextAuthProvider("cassandra", "cassandra"), }); // 创建我们的客户端 const client = new Client(cassandraClient); // 设置 keyspace await client.useKeyspace("my_keyspace", { class: "SimpleStrategy", replication_factor: 1, }); // 创建用户模型 const userModel = client.createModel( { id: Field.uuid().partitionKey(), // 分区键,必填 name: Field.text().clusteringKey(), // 聚类键,必填 age: Field.int().optional(), // 可选字段 email: Field.text(), // 普通字段,必填 }, "users" ); type User = Infer<typeof userModel>; // 创建文章模型 const postModel = client.createModel( { id: Field.uuid().partitionKey(), // 分区键,必填 title: Field.text(), // 普通字段,必填 content: Field.text(), // 普通字段,必填 created_at: Field.timestamp(), // 普通字段,必填 }, "posts" ); // 同步所有表结构 await client.syncAllSchemas(); // 创建用户 const user = await userModel.create({ id: uuid(), // 必须提供分区键 name: "张三", // 必须提供聚类键 age: 25, // 可选 email: "zhangsan@example.com" // 必填 }); // 创建文章 await postModel.create({ id: uuid(), title: "测试文章", content: "内容", created_at: new Date(), }); // 查询用户 const foundUser = await userModel.findOne({ id: user.id }); console.log(foundUser); // 关闭连接 await client.close(); ``` ## API 参考 ### 类型推导工具 ORM 库提供了一系列类型推导工具,可以帮助开发者在上层 API 中实现类型安全 #### Infer<M> 从 Model 实例中推断出原始字段类型 ```typescript const userModel = client.createModel({ id: Field.uuid().partitionKey(), name: Field.text().clusteringKey(), age: Field.int().optional(), email: Field.text(), }, "users"); type User = Infer<typeof userModel>; // 推导结果: { id: string; name: string; age?: number; email: string } ``` #### InferPartitionKey<M> 推导分区键字段类型 ```typescript type UserPartitionKey = InferPartitionKey<typeof userModel>; // 推导结果: { id: string } ``` #### InferClusteringKey<M> 推导聚类键字段类型 ```typescript type UserClusteringKey = InferClusteringKey<typeof userModel>; // 推导结果: { name: string } ``` #### InferNonPartitionFields<S> 推导非分区键字段类型 ```typescript type UserFields = { id: { type: "uuid"; flags: { partitionKey: true } }; name: { type: "text" }; age: { type: "int" }; }; type NonPartitionFields = InferNonPartitionFields<UserFields>; // 推导结果: { name: string; age: number } ``` #### InferStaticFields<M> 推导静态字段类型 ```typescript const userModel = client.createModel({ id: Field.uuid().partitionKey(), name: Field.text().static(), // 静态字段 age: Field.int().optional(), email: Field.text(), }, "users"); type UserStaticFields = InferStaticFields<typeof userModel>; // 推导结果: { name: string } ``` 静态列的特点: 1. 在分区级别存储数据,而不是在每一行重复存储 2. 适用于在分区内所有行共享相同值的字段 3. 可以节省存储空间 4. 提高查询效率 这些类型工具可以用于: 1. 在 API 层定义类型安全的接口 2. 在服务层进行类型检查 3. 在数据访问层确保数据一致性 4. 在业务逻辑层进行类型推导 ### Client `Client` 类是对原始 Cassandra 客户端的封装,提供了更高级的 API #### 构造函数 ```typescript constructor(cassandraClient: CassandraClient) ``` #### 方法 - `useKeyspace(keyspace: string, options: KeyspaceOptions): Promise<void>` - 设置当前使用的 keyspace,如果不存在则创建 - `options`: - `class`: 复制策略,可以是 `"SimpleStrategy"` 或 `"NetworkTopologyStrategy"` - `replication_factor`: 复制因子(仅用于 `SimpleStrategy`) - `datacenters`: 数据中心配置(仅用于 `NetworkTopologyStrategy`) - `createModel<S extends Record<string, FieldConfig<keyof TypeMap>>>(schema: S, tableName: string): Model<S>` - 创建并注册一个新的模型 - 返回的模型实例可以直接使用,不需要额外获取 - `syncAllSchemas(): Promise<void>` - 同步所有已注册模型的结构到数据库 - `close(): Promise<void>` - 关闭数据库连接 ### Model `Model` 类提供了对数据库表的操作接口 #### 类型推导示例 ```typescript // 定义模型 schema const userModel = client.createModel({ id: Field.uuid().partitionKey(), // 分区键,必填 name: Field.text().clusteringKey(), // 聚类键,必填 age: Field.int().optional(), // 可选字段 email: Field.text(), // 普通字段,必填 }, "users"); // 推导出的类型: type User = { id: string; // 分区键,必填 name: string; // 聚类键,必填 age?: number; // 可选字段 email: string; // 普通字段,必填 }; // 分区键类型(用于查询和删除) type PartitionKey = { id: string; }; // 聚类键类型(用于查询和删除) type ClusteringKey = { name: string; }; // 可更新字段类型(用于更新操作) type UpdatableFields = { age?: number; // 可选字段 email: string; // 普通字段 }; ``` #### 方法 - `create(data: User): Promise<void>` - 创建新记录 - 示例: ```typescript await userModel.create({ id: uuid(), // 必须提供分区键 name: "张三", // 必须提供聚类键 age: 25, // 可选 email: "zhangsan@example.com" // 必填 }); ``` - `findOne(partitionKey: PartitionKey, clusteringKey?: Partial<ClusteringKey>): Promise<User | null>` - 查询单条记录 - 示例: ```typescript // 只使用分区键查询 const user = await userModel.findOne({ id: "some-uuid" }); // 使用分区键和聚类键查询 const user = await userModel.findOne( { id: "some-uuid" }, { name: "张三" } ); ``` - `findAll(partitionKey: PartitionKey, clusteringKey?: Partial<ClusteringKey>): Promise<User[]>` - 查询多条记录 - 参数同 `findOne` - `update(partitionKey: PartitionKey, data: Partial<UpdatableFields>): Promise<void>` - 更新记录 - 示例: ```typescript await userModel.update( { id: "some-uuid" }, // 必须提供分区键 { age: 26, // 可以更新可选字段 email: "new@example.com" // 可以更新普通字段 } ); ``` - `delete(partitionKey: PartitionKey, clusteringKey?: Partial<ClusteringKey>): Promise<void>` - 删除记录 - 参数同 `findOne` ### Field `Field` 类提供了创建字段配置的方法 #### 静态方法 - `uuid(): FieldBuilder<"uuid">` - `text(): FieldBuilder<"text">` - `int(): FieldBuilder<"int">` - `bigint(): FieldBuilder<"bigint">` - `float(): FieldBuilder<"float">` - `double(): FieldBuilder<"double">` - `boolean(): FieldBuilder<"boolean">` - `timestamp(): FieldBuilder<"timestamp">` #### 实例方法 - `partitionKey(): this` - 将字段设置为分区键 - 分区键字段是必填的,不能为 null - 示例: ```typescript Field.uuid().partitionKey() // 将 UUID 字段设置为分区键 ``` - `clusteringKey(order?: "ASC" | "DESC"): this` - 将字段设置为聚类键 - 聚类键字段是否必填取决于是否设置了 `optional()` - `order` 可选,指定排序方向 - 示例: ```typescript Field.text().clusteringKey() // 默认升序,必填 Field.text().clusteringKey("DESC") // 降序,必填 Field.text().clusteringKey().optional() // 可选聚类键 ``` - `optional(): this` - 将字段设置为可选 - 可以用于任何类型的字段,包括聚类键 - 示例: ```typescript Field.int().optional() // 将整数字段设置为可选 ``` - `static(): this` - 将字段设置为静态列 - 静态列在分区级别存储,而不是在每一行重复存储 - 适用于在分区内所有行共享相同值的字段 - 示例: ```typescript Field.text().static() // 将文本字段设置为静态列 ``` ## 注意事项 1. 所有模型必须在调用 `syncAllSchemas` 之前创建 2. 创建记录时必须提供所有分区键字段 3. 聚类键字段是否必填取决于是否设置了 `optional()` 4. 更新记录时可以更新非分区键字段(包括聚类键和普通字段) 5. 删除记录时必须提供所有分区键字段 ## 许可证 MIT