@hf-chimera/store 0.1.0 → 0.2.0
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 +171 -360
- package/dist/defaults-CDnbUToo.cjs +175 -0
- package/dist/defaults-CDnbUToo.cjs.map +1 -0
- package/dist/defaults-DkrKTPXY.mjs +91 -0
- package/dist/defaults-DkrKTPXY.mjs.map +1 -0
- package/dist/defaults.cjs +3 -14
- package/dist/defaults.d.cts +16 -42
- package/dist/defaults.d.cts.map +1 -1
- package/dist/defaults.d.mts +33 -0
- package/dist/defaults.d.mts.map +1 -0
- package/dist/defaults.mjs +3 -0
- package/dist/index.cjs +1709 -23
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +634 -2
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +634 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/{src-C74sq0jQ.js → index.mjs} +252 -246
- package/dist/index.mjs.map +1 -0
- package/dist/types-CNGIuRUw.d.mts +117 -0
- package/dist/types-CNGIuRUw.d.mts.map +1 -0
- package/dist/types-CuI5yXiY.d.cts +117 -0
- package/dist/types-CuI5yXiY.d.cts.map +1 -0
- package/package.json +10 -51
- package/.changeset/README.md +0 -8
- package/CHANGELOG.md +0 -98
- package/dist/adapters/react.cjs +0 -70
- package/dist/adapters/react.cjs.map +0 -1
- package/dist/adapters/react.d.cts +0 -15
- package/dist/adapters/react.d.cts.map +0 -1
- package/dist/adapters/react.d.ts +0 -15
- package/dist/adapters/react.d.ts.map +0 -1
- package/dist/adapters/react.js +0 -69
- package/dist/adapters/react.js.map +0 -1
- package/dist/adapters/vue.cjs +0 -92
- package/dist/adapters/vue.cjs.map +0 -1
- package/dist/adapters/vue.d.cts +0 -19
- package/dist/adapters/vue.d.cts.map +0 -1
- package/dist/adapters/vue.d.ts +0 -19
- package/dist/adapters/vue.d.ts.map +0 -1
- package/dist/adapters/vue.js +0 -91
- package/dist/adapters/vue.js.map +0 -1
- package/dist/defaults-C48gY1ow.cjs +0 -372
- package/dist/defaults-C48gY1ow.cjs.map +0 -1
- package/dist/defaults-CLUQg2zK.js +0 -210
- package/dist/defaults-CLUQg2zK.js.map +0 -1
- package/dist/defaults.cjs.map +0 -1
- package/dist/defaults.d.ts +0 -59
- package/dist/defaults.d.ts.map +0 -1
- package/dist/defaults.js +0 -13
- package/dist/defaults.js.map +0 -1
- package/dist/index-BuYMaiND.d.ts +0 -22
- package/dist/index-BuYMaiND.d.ts.map +0 -1
- package/dist/index-C45y61aH.d.ts +0 -821
- package/dist/index-C45y61aH.d.ts.map +0 -1
- package/dist/index-DP6-nR2O.d.cts +0 -821
- package/dist/index-DP6-nR2O.d.cts.map +0 -1
- package/dist/index-FQNcJwA7.d.cts +0 -22
- package/dist/index-FQNcJwA7.d.cts.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -4
- package/dist/params-B-wurzdZ.d.ts +0 -8
- package/dist/params-B-wurzdZ.d.ts.map +0 -1
- package/dist/params-C5dnCvJr.cjs +0 -47
- package/dist/params-C5dnCvJr.cjs.map +0 -1
- package/dist/params-DmOyCS2B.js +0 -13
- package/dist/params-DmOyCS2B.js.map +0 -1
- package/dist/params-uxNE-e4a.d.cts +0 -8
- package/dist/params-uxNE-e4a.d.cts.map +0 -1
- package/dist/qb-D6vPK6P0.cjs +0 -50
- package/dist/qb-D6vPK6P0.cjs.map +0 -1
- package/dist/qb-pchs-vdM.js +0 -45
- package/dist/qb-pchs-vdM.js.map +0 -1
- package/dist/qb.cjs +0 -5
- package/dist/qb.d.cts +0 -3
- package/dist/qb.d.ts +0 -3
- package/dist/qb.js +0 -5
- package/dist/src-C74sq0jQ.js.map +0 -1
- package/dist/src-YxpDmKvq.cjs +0 -1771
- package/dist/src-YxpDmKvq.cjs.map +0 -1
package/README.md
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @hf-chimera/store
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
deduplication and efficient data synchronization. Chimera Store provides a
|
|
5
|
-
powerful API for managing cached data with built-in querying, filtering,
|
|
6
|
-
ordering, and real-time updates.
|
|
3
|
+
Core store library for Chimera Store - a cross-platform, reactive cache management library with intelligent deduplication and efficient data synchronization.
|
|
7
4
|
|
|
8
5
|
## Features
|
|
9
6
|
|
|
10
|
-
- **🔄 Cross-Platform Reactivity**: Works seamlessly across web, mobile, and desktop platforms
|
|
11
7
|
- **💾 Intelligent Cache Management**: Automatic deduplication and memory-efficient caching
|
|
12
|
-
- **🔍 Advanced Querying**: Built-in filtering
|
|
8
|
+
- **🔍 Advanced Querying**: Built-in filtering and sorting support
|
|
13
9
|
- **⚡ Real-Time Updates**: Event-driven architecture with automatic cache invalidation
|
|
14
10
|
- **🎯 Type Safety**: Full TypeScript support with comprehensive type definitions
|
|
15
11
|
- **🛡️ Error Handling**: Robust error handling with detailed error messages
|
|
16
|
-
- **📦 Modular Architecture**: Composable components for flexible integration
|
|
17
12
|
- **🌐 Universal Compatibility**: Works with any data source (REST APIs, GraphQL, WebSockets, etc.)
|
|
18
13
|
|
|
19
14
|
## Installation
|
|
@@ -26,124 +21,82 @@ yarn add @hf-chimera/store
|
|
|
26
21
|
pnpm add @hf-chimera/store
|
|
27
22
|
```
|
|
28
23
|
|
|
24
|
+
## Framework Integrations
|
|
25
|
+
|
|
26
|
+
- **React**: Use [`@hf-chimera/react`](../adapters/react) for React hooks
|
|
27
|
+
- **Vue**: Use [`@hf-chimera/vue`](../adapters/vue) for Vue 3 composables
|
|
28
|
+
- **Query Builder**: Use [`@hf-chimera/query-builder`](../qb) for fluent query building
|
|
29
|
+
|
|
29
30
|
## Quick Start
|
|
30
31
|
|
|
31
32
|
### Basic Setup
|
|
32
33
|
|
|
33
34
|
```typescript
|
|
34
|
-
import {
|
|
35
|
+
import { createChimeraEntityStore } from "@hf-chimera/store";
|
|
35
36
|
|
|
36
|
-
// Define your entity
|
|
37
|
+
// Define your entity type
|
|
37
38
|
type User = {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
type Post = {
|
|
45
|
-
id: string;
|
|
46
|
-
title: string;
|
|
47
|
-
content: string;
|
|
48
|
-
authorId: string;
|
|
49
|
-
createdAt: Date;
|
|
39
|
+
id: number;
|
|
40
|
+
name: string;
|
|
41
|
+
email: string;
|
|
42
|
+
age: number;
|
|
50
43
|
};
|
|
51
44
|
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
//
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
},
|
|
108
|
-
posts: {
|
|
109
|
-
collectionFetcher: async (params, requestParams) => {
|
|
110
|
-
const response = await fetch(`/api/posts`, {
|
|
111
|
-
signal: requestParams.signal,
|
|
112
|
-
});
|
|
113
|
-
return { data: await response.json() };
|
|
114
|
-
},
|
|
115
|
-
itemFetcher: async (params, requestParams) => {
|
|
116
|
-
const response = await fetch(`/api/posts/${params.id}`, {
|
|
117
|
-
signal: requestParams.signal,
|
|
118
|
-
});
|
|
119
|
-
return { data: await response.json() };
|
|
120
|
-
},
|
|
121
|
-
itemUpdater: async (item, requestParams) => {
|
|
122
|
-
const response = await fetch(`/api/posts/${item.id}`, {
|
|
123
|
-
method: 'PUT',
|
|
124
|
-
body: JSON.stringify(item),
|
|
125
|
-
signal: requestParams.signal,
|
|
126
|
-
});
|
|
127
|
-
return { data: await response.json() };
|
|
128
|
-
},
|
|
129
|
-
itemDeleter: async (id, requestParams) => {
|
|
130
|
-
await fetch(`/api/posts/${id}`, {
|
|
131
|
-
method: 'DELETE',
|
|
132
|
-
signal: requestParams.signal,
|
|
133
|
-
});
|
|
134
|
-
return { result: { id, success: true } };
|
|
135
|
-
},
|
|
136
|
-
itemCreator: async (item, requestParams) => {
|
|
137
|
-
const response = await fetch(`/api/posts`, {
|
|
138
|
-
method: 'POST',
|
|
139
|
-
body: JSON.stringify(item),
|
|
140
|
-
signal: requestParams.signal,
|
|
141
|
-
});
|
|
142
|
-
return { data: await response.json() };
|
|
143
|
-
},
|
|
144
|
-
},
|
|
145
|
-
},
|
|
146
|
-
},
|
|
45
|
+
// Create an entity store
|
|
46
|
+
const userStore = createChimeraEntityStore<"user", User>({
|
|
47
|
+
name: "user",
|
|
48
|
+
idGetter: "id", // Can be a string (property name) or function
|
|
49
|
+
trustQuery: true,
|
|
50
|
+
|
|
51
|
+
// Collection fetcher - fetch multiple items
|
|
52
|
+
collectionFetcher: async (params, requestParams) => {
|
|
53
|
+
const response = await fetch(`/api/users`, {
|
|
54
|
+
method: "POST",
|
|
55
|
+
headers: { "Content-Type": "application/json" },
|
|
56
|
+
body: JSON.stringify({ filter: params.filter, order: params.order }),
|
|
57
|
+
signal: requestParams.signal,
|
|
58
|
+
});
|
|
59
|
+
return { data: await response.json() };
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
// Item fetcher - fetch single item by ID
|
|
63
|
+
itemFetcher: async (params, requestParams) => {
|
|
64
|
+
const response = await fetch(`/api/users/${params.id}`, {
|
|
65
|
+
signal: requestParams.signal,
|
|
66
|
+
});
|
|
67
|
+
return { data: await response.json() };
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
// Item creator - create new item
|
|
71
|
+
itemCreator: async (item, requestParams) => {
|
|
72
|
+
const response = await fetch(`/api/users`, {
|
|
73
|
+
method: "POST",
|
|
74
|
+
headers: { "Content-Type": "application/json" },
|
|
75
|
+
body: JSON.stringify(item),
|
|
76
|
+
signal: requestParams.signal,
|
|
77
|
+
});
|
|
78
|
+
return { data: await response.json() };
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
// Item updater - update existing item
|
|
82
|
+
itemUpdater: async (item, requestParams) => {
|
|
83
|
+
const response = await fetch(`/api/users/${item.id}`, {
|
|
84
|
+
method: "PUT",
|
|
85
|
+
headers: { "Content-Type": "application/json" },
|
|
86
|
+
body: JSON.stringify(item),
|
|
87
|
+
signal: requestParams.signal,
|
|
88
|
+
});
|
|
89
|
+
return { data: await response.json() };
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
// Item deleter - delete item by ID
|
|
93
|
+
itemDeleter: async (id, requestParams) => {
|
|
94
|
+
await fetch(`/api/users/${id}`, {
|
|
95
|
+
method: "DELETE",
|
|
96
|
+
signal: requestParams.signal,
|
|
97
|
+
});
|
|
98
|
+
return { result: { id, success: true } };
|
|
99
|
+
},
|
|
147
100
|
});
|
|
148
101
|
```
|
|
149
102
|
|
|
@@ -151,76 +104,68 @@ const store = new ChimeraStore<EntityMap>({
|
|
|
151
104
|
|
|
152
105
|
```typescript
|
|
153
106
|
import {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
} from '@hf-chimera/store';
|
|
160
|
-
|
|
161
|
-
// Get a repository for a specific entity
|
|
162
|
-
const userRepo = store.from('users');
|
|
163
|
-
const postRepo = store.from('posts');
|
|
107
|
+
chimeraCreateConjunction,
|
|
108
|
+
chimeraCreateOperator,
|
|
109
|
+
chimeraCreateOrderBy,
|
|
110
|
+
ChimeraOrderNulls,
|
|
111
|
+
} from "@hf-chimera/store";
|
|
164
112
|
|
|
165
113
|
// Create a new user
|
|
166
|
-
const newUserQuery =
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
114
|
+
const newUserQuery = userStore.createItem({
|
|
115
|
+
name: "John Doe",
|
|
116
|
+
email: "john@example.com",
|
|
117
|
+
age: 30,
|
|
170
118
|
});
|
|
171
119
|
|
|
172
120
|
// Listen for creation events
|
|
173
|
-
newUserQuery.on(
|
|
174
|
-
|
|
121
|
+
newUserQuery.on("created", (query) => {
|
|
122
|
+
console.log("User created:", query.data);
|
|
175
123
|
});
|
|
176
124
|
|
|
177
125
|
// Get a specific user
|
|
178
|
-
const userQuery =
|
|
126
|
+
const userQuery = userStore.getItem(123);
|
|
179
127
|
|
|
180
128
|
// Listen for data updates
|
|
181
|
-
userQuery.on(
|
|
182
|
-
|
|
129
|
+
userQuery.on("ready", (query) => {
|
|
130
|
+
console.log("User loaded:", query.data);
|
|
183
131
|
});
|
|
184
132
|
|
|
185
133
|
// Update user data
|
|
186
|
-
userQuery.mutable.name =
|
|
134
|
+
userQuery.mutable.name = "Jane Doe";
|
|
187
135
|
await userQuery.commit();
|
|
188
136
|
|
|
189
137
|
// Get a collection with filtering and sorting
|
|
190
|
-
const activeUsersQuery =
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
chimeraCreateOrderBy('name', false, ChimeraOrderNulls.Last),
|
|
196
|
-
],
|
|
138
|
+
const activeUsersQuery = userStore.getCollection({
|
|
139
|
+
filter: chimeraCreateConjunction("and", [
|
|
140
|
+
chimeraCreateOperator("gte", "age", 18),
|
|
141
|
+
]),
|
|
142
|
+
order: [chimeraCreateOrderBy("name", false, ChimeraOrderNulls.Last)],
|
|
197
143
|
});
|
|
198
144
|
|
|
199
145
|
// Listen for collection updates
|
|
200
|
-
activeUsersQuery.on(
|
|
201
|
-
|
|
146
|
+
activeUsersQuery.on("updated", (query, items, oldItems) => {
|
|
147
|
+
console.log("Active users updated:", items);
|
|
202
148
|
});
|
|
203
149
|
|
|
204
150
|
// External updates (e.g., from WebSocket)
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
151
|
+
userStore.updateOne({
|
|
152
|
+
id: 123,
|
|
153
|
+
name: "Updated Name",
|
|
154
|
+
email: "updated@example.com",
|
|
155
|
+
age: 31,
|
|
210
156
|
});
|
|
211
157
|
```
|
|
212
158
|
|
|
213
159
|
## Core Concepts
|
|
214
160
|
|
|
215
|
-
### Store
|
|
161
|
+
### Entity Store
|
|
216
162
|
|
|
217
|
-
|
|
163
|
+
Each entity type has its own `ChimeraEntityStore` instance created via `createChimeraEntityStore`. This provides:
|
|
218
164
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
5. **Events**: Real-time updates and state synchronization
|
|
165
|
+
- **Isolated caching** per entity type
|
|
166
|
+
- **Type-safe operations** for that specific entity
|
|
167
|
+
- **Event-driven updates** for real-time synchronization
|
|
168
|
+
- **Query management** with automatic deduplication
|
|
224
169
|
|
|
225
170
|
### Query Types
|
|
226
171
|
|
|
@@ -247,34 +192,66 @@ Flexible ordering with support for:
|
|
|
247
192
|
|
|
248
193
|
## API Reference
|
|
249
194
|
|
|
250
|
-
###
|
|
195
|
+
### createChimeraEntityStore
|
|
251
196
|
|
|
252
|
-
The main
|
|
253
|
-
operations.
|
|
197
|
+
The main function to create an entity store instance.
|
|
254
198
|
|
|
255
|
-
####
|
|
199
|
+
#### Signature
|
|
256
200
|
|
|
257
201
|
```typescript
|
|
258
|
-
|
|
202
|
+
function createChimeraEntityStore<
|
|
203
|
+
TEntityName extends string,
|
|
204
|
+
TItem extends object,
|
|
205
|
+
>(
|
|
206
|
+
config: ChimeraQueryEntityConfig<TEntityName, TItem, OperatorsMap>,
|
|
207
|
+
): ChimeraEntityStore<TEntityName, TItem, OperatorsMap>;
|
|
259
208
|
```
|
|
260
209
|
|
|
261
|
-
####
|
|
210
|
+
#### Parameters
|
|
262
211
|
|
|
263
|
-
- `
|
|
264
|
-
- `
|
|
265
|
-
- `
|
|
266
|
-
- `
|
|
267
|
-
- `
|
|
212
|
+
- `config`: Entity configuration object containing:
|
|
213
|
+
- `name`: Entity name (string)
|
|
214
|
+
- `idGetter`: Property name (string) or function to extract ID from entity
|
|
215
|
+
- `trustQuery`: Whether to trust query results (boolean)
|
|
216
|
+
- `collectionFetcher`: Function to fetch multiple items
|
|
217
|
+
- `itemFetcher`: Function to fetch single item by ID
|
|
218
|
+
- `itemCreator`: Function to create new item
|
|
219
|
+
- `itemUpdater`: Function to update existing item
|
|
220
|
+
- `itemDeleter`: Function to delete item by ID
|
|
221
|
+
- Optional: `batchedCreator`, `batchedUpdater`, `batchedDeleter` for batch operations
|
|
222
|
+
- Optional: `updateDebounceTimeout` for debouncing updates
|
|
268
223
|
|
|
269
|
-
|
|
224
|
+
#### Returns
|
|
270
225
|
|
|
271
|
-
|
|
226
|
+
`ChimeraEntityStore<TEntityName, TItem, OperatorsMap>` instance
|
|
227
|
+
|
|
228
|
+
### ChimeraEntityStore
|
|
229
|
+
|
|
230
|
+
Entity-specific store with query capabilities.
|
|
231
|
+
|
|
232
|
+
#### Properties
|
|
233
|
+
|
|
234
|
+
- `name`: Entity name (readonly)
|
|
272
235
|
|
|
273
236
|
#### Methods
|
|
274
237
|
|
|
275
238
|
- `createItem(item: DeepPartial<Item>, meta?: any)`: Create new item
|
|
276
239
|
- `getItem(id: ChimeraEntityId, meta?: any)`: Get single item
|
|
277
240
|
- `getCollection(params: ChimeraCollectionParams)`: Get filtered/sorted collection
|
|
241
|
+
- `updateOne(item: Item)`: Update single item externally
|
|
242
|
+
- `updateMany(items: Item[])`: Update multiple items externally
|
|
243
|
+
- `deleteOne(id: ChimeraEntityId)`: Delete single item externally
|
|
244
|
+
- `deleteMany(ids: ChimeraEntityId[])`: Delete multiple items externally
|
|
245
|
+
- `updateMixed(toAdd: Item[], toDelete: ChimeraEntityId[])`: Mixed update/delete operation
|
|
246
|
+
|
|
247
|
+
#### Events
|
|
248
|
+
|
|
249
|
+
- `initialized`: Store initialized
|
|
250
|
+
- `itemAdded`: Item added to cache
|
|
251
|
+
- `itemUpdated`: Item updated
|
|
252
|
+
- `updated`: Multiple items updated
|
|
253
|
+
- `itemDeleted`: Item deleted
|
|
254
|
+
- `deleted`: Multiple items deleted
|
|
278
255
|
|
|
279
256
|
### ChimeraItemQuery
|
|
280
257
|
|
|
@@ -287,6 +264,7 @@ Represents a single item query with full CRUD operations.
|
|
|
287
264
|
- `state`: Current query state
|
|
288
265
|
- `ready`: Whether data is available
|
|
289
266
|
- `inProgress`: Whether operation is in progress
|
|
267
|
+
- `id`: Item ID
|
|
290
268
|
|
|
291
269
|
#### Methods
|
|
292
270
|
|
|
@@ -355,119 +333,22 @@ Collection queries implement the standard Array interface:
|
|
|
355
333
|
|
|
356
334
|
## Advanced Usage
|
|
357
335
|
|
|
358
|
-
### Custom Filter Operators
|
|
359
|
-
|
|
360
|
-
```typescript
|
|
361
|
-
const customFilterConfig = {
|
|
362
|
-
...chimeraDefaultFilterConfig,
|
|
363
|
-
operators: {
|
|
364
|
-
...chimeraDefaultFilterConfig.operators,
|
|
365
|
-
// Custom operator for text search
|
|
366
|
-
textSearch: (text: string, searchTerm: string) =>
|
|
367
|
-
text.toLowerCase().includes(searchTerm.toLowerCase()),
|
|
368
|
-
},
|
|
369
|
-
};
|
|
370
|
-
|
|
371
|
-
const store = new ChimeraStore<EntityMap, typeof customFilterConfig.operators>({
|
|
372
|
-
filter: customFilterConfig,
|
|
373
|
-
// ... other config
|
|
374
|
-
});
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
### Complex Filtering Examples
|
|
378
|
-
|
|
379
|
-
```typescript
|
|
380
|
-
import {
|
|
381
|
-
chimeraCreateConjunction,
|
|
382
|
-
chimeraCreateOperator,
|
|
383
|
-
chimeraCreateOrderBy,
|
|
384
|
-
ChimeraOrderNulls
|
|
385
|
-
} from '@hf-chimera/store';
|
|
386
|
-
|
|
387
|
-
// Simple filter: users with age >= 18
|
|
388
|
-
const adultUsers = userRepo.getCollection({
|
|
389
|
-
filter: chimeraCreateOperator('gte', 'age', 18),
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
// Complex filter: active users with specific age range and email domain
|
|
393
|
-
const activeUsers = userRepo.getCollection({
|
|
394
|
-
filter: chimeraCreateConjunction('and', [
|
|
395
|
-
chimeraCreateOperator('gte', 'age', 18),
|
|
396
|
-
chimeraCreateOperator('lte', 'age', 65),
|
|
397
|
-
chimeraCreateOperator('endsWith', 'email', '@company.com'),
|
|
398
|
-
chimeraCreateOperator('eq', 'isActive', true),
|
|
399
|
-
]),
|
|
400
|
-
});
|
|
401
|
-
|
|
402
|
-
// OR filter: users with specific names or email domains
|
|
403
|
-
const specificUsers = userRepo.getCollection({
|
|
404
|
-
filter: chimeraCreateConjunction('or', [
|
|
405
|
-
chimeraCreateOperator('in', 'name', ['John', 'Jane', 'Bob']),
|
|
406
|
-
chimeraCreateOperator('endsWith', 'email', '@gmail.com'),
|
|
407
|
-
]),
|
|
408
|
-
});
|
|
409
|
-
|
|
410
|
-
// Nested filters: complex business logic
|
|
411
|
-
const premiumUsers = userRepo.getCollection({
|
|
412
|
-
filter: chimeraCreateConjunction('and', [
|
|
413
|
-
chimeraCreateOperator('gte', 'age', 21),
|
|
414
|
-
chimeraCreateConjunction('or', [
|
|
415
|
-
chimeraCreateOperator('gte', 'subscriptionLevel', 'premium'),
|
|
416
|
-
chimeraCreateOperator('gte', 'totalSpent', 1000),
|
|
417
|
-
]),
|
|
418
|
-
chimeraCreateOperator('neq', 'status', 'suspended'),
|
|
419
|
-
]),
|
|
420
|
-
});
|
|
421
|
-
|
|
422
|
-
// Text search with multiple conditions
|
|
423
|
-
const searchResults = userRepo.getCollection({
|
|
424
|
-
filter: chimeraCreateConjunction('and', [
|
|
425
|
-
chimeraCreateConjunction('or', [
|
|
426
|
-
chimeraCreateOperator('contains', 'name', searchTerm),
|
|
427
|
-
chimeraCreateOperator('contains', 'email', searchTerm),
|
|
428
|
-
]),
|
|
429
|
-
chimeraCreateOperator('eq', 'isActive', true),
|
|
430
|
-
]),
|
|
431
|
-
order: [
|
|
432
|
-
chimeraCreateOrderBy('name', false, ChimeraOrderNulls.Last),
|
|
433
|
-
chimeraCreateOrderBy('createdAt', true, ChimeraOrderNulls.Last), // newest first
|
|
434
|
-
],
|
|
435
|
-
});
|
|
436
|
-
```
|
|
437
|
-
|
|
438
|
-
### Custom Order Comparators
|
|
439
|
-
|
|
440
|
-
```typescript
|
|
441
|
-
const customOrderConfig = {
|
|
442
|
-
...chimeraDefaultOrderConfig,
|
|
443
|
-
primitiveComparator: (a: unknown, b: unknown, nulls: ChimeraOrderNulls) => {
|
|
444
|
-
// Custom comparison logic
|
|
445
|
-
if (typeof a === 'string' && typeof b === 'string') {
|
|
446
|
-
return a.localeCompare(b, undefined, { numeric: true });
|
|
447
|
-
}
|
|
448
|
-
return chimeraDefaultOrderConfig.primitiveComparator(a, b, nulls);
|
|
449
|
-
},
|
|
450
|
-
};
|
|
451
|
-
```
|
|
452
|
-
|
|
453
336
|
### Event Handling
|
|
454
337
|
|
|
455
338
|
```typescript
|
|
456
339
|
// Listen to store-level events
|
|
457
|
-
|
|
458
|
-
|
|
340
|
+
userStore.on("itemAdded", ({ instance, item }) => {
|
|
341
|
+
console.log("Item added:", item);
|
|
459
342
|
});
|
|
460
343
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
userRepo.on('itemUpdated', (repo, item, oldItem) => {
|
|
464
|
-
console.log('User updated:', item, 'was:', oldItem);
|
|
344
|
+
userStore.on("itemUpdated", ({ instance, item, oldItem }) => {
|
|
345
|
+
console.log("User updated:", item, "was:", oldItem);
|
|
465
346
|
});
|
|
466
347
|
|
|
467
348
|
// Listen to query events
|
|
468
|
-
const userQuery =
|
|
469
|
-
userQuery.on(
|
|
470
|
-
|
|
349
|
+
const userQuery = userStore.getItem(123);
|
|
350
|
+
userQuery.on("updated", (query, item, oldItem) => {
|
|
351
|
+
console.log("Query updated:", item);
|
|
471
352
|
});
|
|
472
353
|
```
|
|
473
354
|
|
|
@@ -475,85 +356,21 @@ userQuery.on('updated', (query, item, oldItem) => {
|
|
|
475
356
|
|
|
476
357
|
```typescript
|
|
477
358
|
// Optimistic update with rollback
|
|
478
|
-
const userQuery =
|
|
359
|
+
const userQuery = userStore.getItem(123);
|
|
479
360
|
|
|
480
361
|
// Update optimistically
|
|
481
|
-
userQuery.mutable.name =
|
|
362
|
+
userQuery.mutable.name = "New Name";
|
|
482
363
|
|
|
483
364
|
try {
|
|
484
|
-
|
|
485
|
-
|
|
365
|
+
await userQuery.commit();
|
|
366
|
+
console.log("Update successful");
|
|
486
367
|
} catch (error) {
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
368
|
+
// Rollback on error
|
|
369
|
+
await userQuery.refetch();
|
|
370
|
+
console.log("Update failed, rolled back");
|
|
490
371
|
}
|
|
491
372
|
```
|
|
492
373
|
|
|
493
|
-
## Configuration Options
|
|
494
|
-
|
|
495
|
-
### Query Configuration
|
|
496
|
-
|
|
497
|
-
```typescript
|
|
498
|
-
type ConfigExample = {
|
|
499
|
-
query: {
|
|
500
|
-
defaults: {
|
|
501
|
-
trustQuery: boolean; // Trust external data providers
|
|
502
|
-
idGetter: ((entityName: string, value: unknown) => string | number) | string; // Default ID getter
|
|
503
|
-
collectionFetcher?: (params: any, request: {
|
|
504
|
-
signal?: AbortSignal
|
|
505
|
-
}) => Promise<{ data: any[] }>;
|
|
506
|
-
itemFetcher?: (params: any, request: {
|
|
507
|
-
signal?: AbortSignal
|
|
508
|
-
}) => Promise<{ data: any }>;
|
|
509
|
-
itemUpdater?: (item: any, request: { signal?: AbortSignal }) => Promise<{
|
|
510
|
-
data: any
|
|
511
|
-
}>;
|
|
512
|
-
itemDeleter?: (id: string | number, request: {
|
|
513
|
-
signal?: AbortSignal
|
|
514
|
-
}) => Promise<{ result?: any }>;
|
|
515
|
-
itemCreator?: (item: any, request: { signal?: AbortSignal }) => Promise<{
|
|
516
|
-
data: any
|
|
517
|
-
}>;
|
|
518
|
-
// ... batched operations
|
|
519
|
-
};
|
|
520
|
-
entities: {
|
|
521
|
-
[entityName: string]: {
|
|
522
|
-
// Entity-specific overrides
|
|
523
|
-
};
|
|
524
|
-
};
|
|
525
|
-
};
|
|
526
|
-
};
|
|
527
|
-
```
|
|
528
|
-
|
|
529
|
-
### Filter Configuration
|
|
530
|
-
|
|
531
|
-
```typescript
|
|
532
|
-
type FilterConfigExample = {
|
|
533
|
-
filter: {
|
|
534
|
-
operators: {
|
|
535
|
-
eq: <T>(a: T, b: T) => boolean;
|
|
536
|
-
neq: <T>(a: T, b: T) => boolean;
|
|
537
|
-
gt?: (a: number, b: number) => boolean;
|
|
538
|
-
// ... custom operators
|
|
539
|
-
};
|
|
540
|
-
getFilterKey?: (input: unknown) => string; // Cache key generator for filters
|
|
541
|
-
getOperatorKey?: (input: unknown) => string; // Cache key generator for operators
|
|
542
|
-
};
|
|
543
|
-
};
|
|
544
|
-
```
|
|
545
|
-
|
|
546
|
-
### Order Configuration
|
|
547
|
-
|
|
548
|
-
```typescript
|
|
549
|
-
type OrderConfigExample = {
|
|
550
|
-
order: {
|
|
551
|
-
primitiveComparator: (a: unknown, b: unknown, nulls: ChimeraOrderNulls) => number; // Custom comparator
|
|
552
|
-
getKey: (input: unknown) => string; // Cache key generator
|
|
553
|
-
};
|
|
554
|
-
};
|
|
555
|
-
```
|
|
556
|
-
|
|
557
374
|
## Performance Considerations
|
|
558
375
|
|
|
559
376
|
### Memory Management
|
|
@@ -564,7 +381,7 @@ type OrderConfigExample = {
|
|
|
564
381
|
|
|
565
382
|
### Caching Strategy
|
|
566
383
|
|
|
567
|
-
- Collection queries are cached by
|
|
384
|
+
- Collection queries are cached by filter/order combination
|
|
568
385
|
- Item queries are cached by ID
|
|
569
386
|
- Cache keys are generated automatically for optimal performance
|
|
570
387
|
|
|
@@ -572,6 +389,7 @@ type OrderConfigExample = {
|
|
|
572
389
|
|
|
573
390
|
- Batch operations for multiple updates
|
|
574
391
|
- Optimistic updates for better UX
|
|
392
|
+
- Debounced updates to reduce API calls
|
|
575
393
|
|
|
576
394
|
## Browser Support
|
|
577
395
|
|
|
@@ -579,20 +397,13 @@ type OrderConfigExample = {
|
|
|
579
397
|
- **Node.js**: 14.17.0+ with `--harmony-weak-refs` flag, 16.0.0+ stable
|
|
580
398
|
- **TypeScript**: 4.5+ recommended
|
|
581
399
|
|
|
582
|
-
##
|
|
400
|
+
## Learn More
|
|
583
401
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
5. Submit a pull request
|
|
402
|
+
- [Main Documentation](../../README.md)
|
|
403
|
+
- [React Integration](../adapters/react/README.md)
|
|
404
|
+
- [Vue Integration](../adapters/vue/README.md)
|
|
405
|
+
- [Query Builder](../qb/README.md)
|
|
589
406
|
|
|
590
407
|
## License
|
|
591
408
|
|
|
592
|
-
MIT License — see [LICENSE](LICENSE) file for details.
|
|
593
|
-
|
|
594
|
-
## Support
|
|
595
|
-
|
|
596
|
-
- **Issues**: [GitHub Issues](https://github.com/hf-chimera/store/issues)
|
|
597
|
-
- **Documentation**: [GitHub Wiki](https://github.com/hf-chimera/store/wiki)
|
|
598
|
-
- **Discussions**: [GitHub Discussions](https://github.com/hf-chimera/store/discussions)
|
|
409
|
+
MIT License — see [LICENSE](../../LICENSE) file for details.
|