@iss-ai/easy-web-store 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,15 +1,17 @@
1
1
  # @iss-ai/easy-web-store
2
2
 
3
- 一个简单高效的 Web 应用状态管理库,基于 Dexie.js 封装 IndexedDB,提供便捷的 CRUD 操作。
3
+ 一个简单高效的 Web 应用数据存储库,提供多种存储方式(IndexedDB、localStorage、sessionStorage、Cookies、内存),支持完整的 CRUD 操作和丰富的查询条件。
4
4
 
5
5
  ## ✨ 特性
6
6
 
7
7
  - 🚀 **简单易用**:直观的 API 设计,快速上手
8
- - 💾 **持久化存储**:基于 IndexedDB,数据持久保存在浏览器
8
+ - 💾 **多种存储方式**:支持 IndexedDB、localStorage、sessionStorage、Cookies、内存存储
9
9
  - 🔧 **TypeScript 支持**:完整的类型定义
10
- - 📦 **零依赖**:仅依赖 Dexie.js
10
+ - 📦 **轻量级**:零依赖(IndexedDB 版本仅依赖 Dexie.js
11
11
  - 🌐 **跨浏览器**:支持现代浏览器(Last 2 versions, > 5%, not IE <= 9)
12
12
  - 📄 **完整 CRUD**:提供保存、查询、更新、删除等完整数据操作
13
+ - 🔍 **丰富查询**:支持多种查询操作符($eq, $neq, $gt, $lt, $in, $like, $regexp 等)
14
+ - 📃 **分页支持**:内置分页功能
13
15
 
14
16
  ## 📦 安装
15
17
 
@@ -32,280 +34,310 @@ pnpm add @iss-ai/easy-web-store
32
34
  import { EasyDexieStore } from '@iss-ai/easy-web-store';
33
35
 
34
36
  // 定义数据类型
35
- interface Product {
37
+ interface User {
36
38
  id?: string | number;
37
39
  name: string;
38
- price: number;
39
- category: string;
40
+ email: string;
41
+ age: number;
40
42
  createTime?: Date;
41
43
  updateTime?: Date;
42
44
  }
43
45
 
44
- // 创建数据存储实例
45
- const productStore = new EasyDexieStore<Product>('products', 'my-db');
46
+ // 创建数据存储实例(IndexedDB)
47
+ const userStore = new EasyDexieStore<User>('users', 'my-app-db');
46
48
 
47
49
  // 保存数据
48
- await productStore.save({
49
- name: 'iPhone 15',
50
- price: 6999,
51
- category: '电子产品'
50
+ const user = await userStore.save({
51
+ name: 'John',
52
+ email: 'john@example.com',
53
+ age: 25
52
54
  });
53
55
 
54
56
  // 查询数据
55
- const products = await productStore.getList({
56
- where: { category: '电子产品' },
57
- sort: { price: -1 }
57
+ const users = await userStore.getList({
58
+ where: { age: { $gt: 18 } },
59
+ sort: { createTime: -1 }
58
60
  });
59
61
 
60
- // 更新数据
61
- await productStore.update({ price: 6799 }, { name: 'iPhone 15' });
62
+ // 更新数据(更新所有符合条件的记录)
63
+ await userStore.update({ age: 26 }, { name: 'John' });
62
64
 
63
65
  // 删除数据
64
- await productStore.delete({ category: '电子产品' });
66
+ await userStore.delete({ name: 'John' });
65
67
  ```
66
68
 
67
- ## 📖 API 文档
68
-
69
- ### EasyDexieStore 构造函数
69
+ ### 使用不同的存储方式
70
70
 
71
71
  ```typescript
72
- new EasyDexieStore<T>(tableName?: string, dbName?: string, tableSchema?: string)
73
- ```
72
+ import {
73
+ EasyDexieStore, // IndexedDB(推荐,容量大,支持复杂查询)
74
+ EasyMemoryStore, // 内存存储(应用重启后数据丢失)
75
+ EasyLocalStorage, // localStorage(持久化,约 5MB 容量)
76
+ EasySessionStorage, // sessionStorage(页面关闭后数据丢失)
77
+ EasyCookiesStore // Cookies(小数据量,支持过期时间)
78
+ } from '@iss-ai/easy-web-store';
74
79
 
75
- | 参数 | 类型 | 默认值 | 描述 |
76
- |------|------|--------|------|
77
- | tableName | string | 'store' | 数据表名称 |
78
- | dbName | string | 'easy-store' | 数据库名称 |
79
- | tableSchema | string | undefined | 自定义表结构 |
80
+ // 内存存储 - 适合临时数据
81
+ const memoryStore = new EasyMemoryStore<User>('temp-users');
80
82
 
81
- ### 核心方法
83
+ // localStorage - 适合持久化数据
84
+ const localStore = new EasyLocalStorage<User>('users');
82
85
 
83
- #### save() - 保存或更新单条数据
86
+ // sessionStorage - 适合会话数据
87
+ const sessionStore = new EasySessionStorage<User>('session-users');
84
88
 
85
- ```typescript
86
- async save(data: Omit<T, 'id'> | T): Promise<T>
89
+ // Cookies - 适合小数据量、需要与服务端交互的场景
90
+ const cookiesStore = new EasyCookiesStore<User>('cookie-users');
87
91
  ```
88
92
 
89
- - **新增数据**:不指定 `id` 字段
90
- - **更新数据**:指定已有数据的 `id` 字段
91
- - 自动处理 `createTime` 和 `updateTime`
93
+ ## 📖 API 文档
92
94
 
93
- #### saveList() - 批量保存数据
95
+ ### 通用接口
94
96
 
95
- ```typescript
96
- async saveList(dataList: Array<Omit<T, 'id'> | T>): Promise<T[]>
97
- ```
97
+ 所有存储类都实现 `IEasyStore<T>` 接口,提供相同的方法:
98
98
 
99
- 批量添加数据,返回保存后的完整数据列表。
99
+ | 方法 | 描述 | 返回值 |
100
+ |------|------|--------|
101
+ | `save(data)` | 保存或更新单条数据 | `Promise<T>` |
102
+ | `saveList(dataList)` | 批量保存数据 | `Promise<T[]>` |
103
+ | `getList(condition?)` | 获取数据列表 | `Promise<T[]>` |
104
+ | `getInfo(condition)` | 获取单条数据 | `Promise<T \| null>` |
105
+ | `update(data, condition)` | 更新符合条件的数据 | `Promise<T \| null>` |
106
+ | `delete(condition)` | 删除符合条件的数据 | `Promise<number>` |
107
+ | `count(condition)` | 统计符合条件的数量 | `Promise<number>` |
108
+ | `getPage(condition)` | 分页获取数据 | `Promise<IPage<T>>` |
109
+ | `clear()` | 清空所有数据 | `Promise<void>` |
100
110
 
101
- #### getList() - 获取数据列表
111
+ ### 查询条件
102
112
 
103
113
  ```typescript
104
- async getList(condition?: IQueryCondition<T>): Promise<T[]>
114
+ interface IQueryCondition<T> {
115
+ where?: Partial<T>; // 查询条件
116
+ sort?: Record<string, 1 | -1>; // 排序规则
117
+ page?: number; // 页码(从 1 开始)
118
+ pageSize?: number; // 每页数量
119
+ fields?: Partial<Record<keyof T, 1>>; // 字段选择
120
+ }
105
121
  ```
106
122
 
107
- 支持以下查询方式:
123
+ ### 查询操作符
108
124
 
109
- - **获取全部**:无参数查询
110
- - **条件查询**:按字段值过滤
111
- - **排序查询**:按指定字段排序
112
- - **字段选择**:只返回指定字段
113
- - **复杂条件**:使用操作符(`$gt`, `$lt`, `$in`, `$like` 等)
114
-
115
- 示例:
125
+ | 操作符 | 说明 | 示例 |
126
+ |--------|------|------|
127
+ | `$eq` | 等于 | `{ age: { $eq: 18 } }` |
128
+ | `$neq` | 不等于 | `{ age: { $neq: 18 } }` |
129
+ | `$gt` | 大于 | `{ age: { $gt: 18 } }` |
130
+ | `$gte` | 大于等于 | `{ age: { $gte: 18 } }` |
131
+ | `$lt` | 小于 | `{ age: { $lt: 18 } }` |
132
+ | `$lte` | 小于等于 | `{ age: { $lte: 18 } }` |
133
+ | `$in` | 在数组中 | `{ age: { $in: [18, 25, 30] } }` |
134
+ | `$nin` | 不在数组中 | `{ age: { $nin: [18, 25] } }` |
135
+ | `$like` | 包含字符串 | `{ name: { $like: 'John' } }` |
136
+ | `$likeIgnoreCase` | 包含字符串(忽略大小写) | `{ name: { $likeIgnoreCase: 'john' } }` |
137
+ | `$startsWith` | 以指定字符串开头 | `{ name: { $startsWith: 'J' } }` |
138
+ | `$startsWithIgnoreCase` | 以指定字符串开头(忽略大小写) | `{ name: { $startsWithIgnoreCase: 'j' } }` |
139
+ | `$regexp` | 正则表达式匹配 | `{ email: { $regexp: /^[a-z]+@/ } }` |
140
+
141
+ ### 各类存储特点
142
+
143
+ #### EasyDexieStore (IndexedDB)
144
+
145
+ - **容量**:大容量(通常 50MB+)
146
+ - **持久化**:是
147
+ - **查询能力**:支持完整查询操作符
148
+ - **适用场景**:大量数据存储、复杂查询
116
149
 
117
150
  ```typescript
118
- // 获取全部
119
- const all = await store.getList();
120
-
121
- // 条件查询
122
- const filtered = await store.getList({
123
- where: { category: '电子产品' }
124
- });
125
-
126
- // 排序查询
127
- const sorted = await store.getList({
128
- sort: { price: -1 } // -1 降序,1 升序
129
- });
130
-
131
- // 复杂条件
132
- const complex = await store.getList({
133
- where: {
134
- price: { $gt: 1000, $lt: 10000 }
135
- }
136
- });
151
+ const store = new EasyDexieStore<User>('users', 'my-db', 'id,createTime,updateTime,name,email');
137
152
  ```
138
153
 
139
- #### getInfo() - 获取单条信息
154
+ #### EasyMemoryStore (内存)
155
+
156
+ - **容量**:受限于浏览器内存
157
+ - **持久化**:否(应用重启后丢失)
158
+ - **查询能力**:支持完整查询操作符
159
+ - **适用场景**:临时数据、缓存
140
160
 
141
161
  ```typescript
142
- async getInfo(condition: Partial<T>): Promise<T | null>
162
+ const store = new EasyMemoryStore<User>('temp-data');
143
163
  ```
144
164
 
145
- 根据条件获取第一条匹配的数据,不存在则返回 `null`。
165
+ #### EasyLocalStorage (localStorage)
146
166
 
147
- #### update() - 更新数据
167
+ - **容量**:约 5MB
168
+ - **持久化**:是
169
+ - **查询能力**:支持完整查询操作符
170
+ - **适用场景**:中等数据量、需要持久化
148
171
 
149
172
  ```typescript
150
- async update(data: Record<string, any>, condition: Partial<T>): Promise<T | null>
173
+ const store = new EasyLocalStorage<User>('user-preferences');
151
174
  ```
152
175
 
153
- 根据条件查找数据并更新指定字段,自动更新 `updateTime`。
176
+ #### EasySessionStorage (sessionStorage)
154
177
 
155
- #### delete() - 删除数据
178
+ - **容量**:约 5MB
179
+ - **持久化**:否(页面关闭后丢失)
180
+ - **查询能力**:支持完整查询操作符
181
+ - **适用场景**:会话数据、临时表单
156
182
 
157
183
  ```typescript
158
- async delete(condition: Partial<T>): Promise<number>
184
+ const store = new EasySessionStorage<User>('session-data');
159
185
  ```
160
186
 
161
- 根据条件删除匹配的数据,返回删除的记录数。
187
+ #### EasyCookiesStore (Cookies)
162
188
 
163
- #### count() - 数据统计
189
+ - **容量**:约 4KB
190
+ - **持久化**:可设置过期时间
191
+ - **查询能力**:支持完整查询操作符
192
+ - **适用场景**:小数据量、需要与服务端共享
164
193
 
165
194
  ```typescript
166
- async count(condition: Partial<T>): Promise<number>
195
+ const store = new EasyCookiesStore<User>('user-settings');
167
196
  ```
168
197
 
169
- 统计符合条件的记录数,空条件统计全部。
198
+ ## 📝 使用示例
170
199
 
171
- #### getPage() - 分页查询
200
+ ### 完整 CRUD 示例
172
201
 
173
202
  ```typescript
174
- async getPage(condition: IQueryCondition<T>): Promise<IPage<T>>
175
- ```
176
-
177
- 返回分页结果:
203
+ import { EasyDexieStore } from '@iss-ai/easy-web-store';
178
204
 
179
- ```typescript
180
- {
181
- list: T[], // 数据列表
182
- total: number, // 总记录数
183
- page: number, // 当前页码
184
- size: number, // 每页数量
185
- totalPages: number // 总页数
205
+ interface Product {
206
+ id?: string;
207
+ name: string;
208
+ price: number;
209
+ category: string;
210
+ tags?: string[];
211
+ createTime?: Date;
212
+ updateTime?: Date;
186
213
  }
187
- ```
188
214
 
189
- #### clear() - 清空所有数据
215
+ const productStore = new EasyDexieStore<Product>('products', 'shop-db');
190
216
 
191
- ```typescript
192
- async clear(): Promise<void>
193
- ```
217
+ // 创建
218
+ await productStore.save({
219
+ name: 'iPhone 15',
220
+ price: 6999,
221
+ category: 'electronics',
222
+ tags: ['apple', 'smartphone']
223
+ });
194
224
 
195
- 清空表中所有数据。
225
+ // 批量创建
226
+ await productStore.saveList([
227
+ { name: 'MacBook Pro', price: 14999, category: 'electronics' },
228
+ { name: 'AirPods', price: 1299, category: 'electronics' }
229
+ ]);
196
230
 
197
- #### close() - 关闭数据库连接
231
+ // 查询 - 简单条件
232
+ const electronics = await productStore.getList({
233
+ where: { category: 'electronics' }
234
+ });
198
235
 
199
- ```typescript
200
- close(): void
201
- ```
236
+ // 查询 - 复杂条件
237
+ const expensiveProducts = await productStore.getList({
238
+ where: {
239
+ price: { $gt: 5000 },
240
+ name: { $likeIgnoreCase: 'iphone' }
241
+ },
242
+ sort: { price: -1 }
243
+ });
202
244
 
203
- 关闭数据库连接。
245
+ // 查询 - 正则表达式
246
+ const appleProducts = await productStore.getList({
247
+ where: { name: { $regexp: /apple/i } }
248
+ });
204
249
 
205
- ## 🔍 查询操作符
250
+ // 分页查询
251
+ const page1 = await productStore.getPage({
252
+ where: { category: 'electronics' },
253
+ page: 1,
254
+ pageSize: 10,
255
+ sort: { createTime: -1 }
256
+ });
206
257
 
207
- | 操作符 | 描述 | 示例 |
208
- |--------|------|------|
209
- | `$ne` | 不等于 | `{ price: { $ne: 100 } }` |
210
- | `$gt` | 大于 | `{ price: { $gt: 100 } }` |
211
- | `$gte` | 大于等于 | `{ price: { $gte: 100 } }` |
212
- | `$lt` | 小于 | `{ price: { $lt: 100 } }` |
213
- | `$lte` | 小于等于 | `{ price: { $lte: 100 } }` |
214
- | `$in` | 在数组中 | `{ category: { $in: ['A', 'B'] } }` |
215
- | `$nin` | 不在数组中 | `{ category: { $nin: ['C'] } }` |
216
- | `$like` | 包含字符串 | `{ name: { $like: 'phone' } }` |
258
+ // 更新
259
+ await productStore.update(
260
+ { price: 6799 },
261
+ { name: 'iPhone 15' }
262
+ );
217
263
 
218
- ## 📋 类型定义
264
+ // 统计
265
+ const count = await productStore.count({ category: 'electronics' });
219
266
 
220
- ### IBase
267
+ // 删除
268
+ await productStore.delete({ category: 'electronics' });
221
269
 
222
- 基础接口,所有数据类型都应继承此接口:
270
+ // 清空
271
+ await productStore.clear();
272
+ ```
273
+
274
+ ### 响应式数据同步示例
223
275
 
224
276
  ```typescript
225
- interface IBase {
226
- id?: string | number;
277
+ import { EasyLocalStorage } from '@iss-ai/easy-web-store';
278
+
279
+ interface Todo {
280
+ id?: string;
281
+ title: string;
282
+ completed: boolean;
227
283
  createTime?: Date;
228
284
  updateTime?: Date;
229
285
  }
230
- ```
231
286
 
232
- ### IQueryCondition
287
+ class TodoStore {
288
+ private store: EasyLocalStorage<Todo>;
289
+ private listeners: Set<() => void> = new Set();
233
290
 
234
- 查询条件接口:
291
+ constructor() {
292
+ this.store = new EasyLocalStorage<Todo>('todos');
293
+ }
235
294
 
236
- ```typescript
237
- interface IQueryCondition<T> {
238
- where?: Partial<T>; // 查询条件
239
- sort?: Record<string, 1 | -1>; // 排序规则
240
- page?: number; // 分页页码(从 1 开始)
241
- pageSize?: number; // 每页数量
242
- fields?: Partial<Record<keyof T, 1>>; // 字段选择
243
- }
244
- ```
295
+ // 订阅数据变化
296
+ subscribe(listener: () => void) {
297
+ this.listeners.add(listener);
298
+ return () => this.listeners.delete(listener);
299
+ }
300
+
301
+ // 通知所有订阅者
302
+ private notify() {
303
+ this.listeners.forEach(listener => listener());
304
+ }
245
305
 
246
- ### IPage
306
+ async addTodo(title: string) {
307
+ await this.store.save({ title, completed: false });
308
+ this.notify();
309
+ }
247
310
 
248
- 分页结果接口:
311
+ async toggleTodo(id: string) {
312
+ const todo = await this.store.getInfo({ id });
313
+ if (todo) {
314
+ await this.store.update({ completed: !todo.completed }, { id });
315
+ this.notify();
316
+ }
317
+ }
249
318
 
250
- ```typescript
251
- interface IPage<T> {
252
- list: T[]; // 数据列表
253
- total: number; // 总记录数
254
- page: number; // 当前页码
255
- size: number; // 每页数量
256
- totalPages: number; // 总页数
319
+ async getTodos() {
320
+ return await this.store.getList({ sort: { createTime: -1 } });
321
+ }
257
322
  }
258
323
  ```
259
324
 
260
- ## 🛠️ 开发
261
-
262
- ### 环境要求
263
-
264
- - Node.js >= 18.0.0
265
- - pnpm (推荐) 或 npm/yarn
266
-
267
- ### 本地开发
325
+ ## 🔧 开发
268
326
 
269
327
  ```bash
270
- # 克隆仓库
271
- git clone https://github.com/your-repo/web-easy-store.git
272
-
273
- # 进入目录
274
- cd web-easy-store
275
-
276
328
  # 安装依赖
277
- pnpm install
329
+ npm install
278
330
 
279
331
  # 构建
280
- pnpm build
281
-
282
- # 运行测试
283
- pnpm test
284
- ```
332
+ npm run build
285
333
 
286
- ### 构建输出
334
+ # 测试
335
+ npm test
287
336
 
337
+ # 类型检查
338
+ npm run tsc
288
339
  ```
289
- lib/
290
- ├── index.cjs.js # CommonJS 模块
291
- ├── index.esm.js # ES 模块
292
- ├── index.umd.js # UMD 模块
293
- ├── index.min.js # 压缩版
294
- └── index.d.ts # TypeScript 类型定义
295
- ```
296
-
297
- ## 📝 示例
298
-
299
- 查看 [`example/`](example/) 目录获取更多使用示例。
300
340
 
301
341
  ## 📄 许可证
302
342
 
303
- MIT License - 详见 [`LICENSE`](LICENSE) 文件。
304
-
305
- ## 🤝 贡献
306
-
307
- 欢迎提交 Issue 和 Pull Request!
308
-
309
- ---
310
-
311
- Built with ❤️ using TypeScript and Dexie.js
343
+ MIT License