@fireflysemantics/slice 17.0.5 → 17.0.7
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 +319 -19
- package/package.json +1 -1
package/README.md
CHANGED
@@ -6,6 +6,12 @@ Lightweight Javascript Reactive State Management for Angular Applications.
|
|
6
6
|
|
7
7
|
If you like the [@fireflysemantics/slice API](https://fireflysemantics.github.io/slice/doc/) please star our [Github Repository](https://github.com/fireflysemantics/slice).
|
8
8
|
|
9
|
+
- [Install](#install)
|
10
|
+
- [Object Store Core Use Cases](#object-store-core-use-cases)
|
11
|
+
- [Entity Store Core Use Cases](#entity-store-core-use-cases)
|
12
|
+
- [Features](#features)
|
13
|
+
- [Documentatino and Media](#firefly-semantics-slice-development-center-media-and-documentation)
|
14
|
+
|
9
15
|
# Install
|
10
16
|
|
11
17
|
|
@@ -28,6 +34,8 @@ npm i @fireflysemantics/slice@lastest nanoid
|
|
28
34
|
|
29
35
|
# Usage
|
30
36
|
|
37
|
+
The project [typedoc](https://fireflysemantics.github.io/slice/typedoc/), in addition to providing more detailed API insight, syntax highlights all the examples provided here, thus you may want to check it out for a richer reading experience.
|
38
|
+
|
31
39
|
## Object Store Core Use Cases
|
32
40
|
|
33
41
|
[Here is a link to the Stackblitz Demo](https://stackblitz.com/edit/typescript-9snt67?file=index.ts)
|
@@ -129,7 +137,316 @@ console.log(`The count is ${OS.count()}`);
|
|
129
137
|
console.log(`The snapshot is ${OS.snapshot(OS.S.K1)}`);
|
130
138
|
```
|
131
139
|
|
140
|
+
## Entity Store Core Use Cases
|
141
|
+
|
142
|
+
[Here is a link to the Stackblitz demo](https://stackblitz.com/edit/typescript-akqgqg?file=index.ts) containing the below demo code. You may also wish to check out the [test cases](https://github.com/fireflysemantics/slice/blob/master/projects/slice/src/lib/EStore.spec.ts) for the entity store which also detail usage scenarios.
|
143
|
+
|
144
|
+
```
|
145
|
+
//============================================
|
146
|
+
// Demo Utilities
|
147
|
+
//============================================
|
148
|
+
|
149
|
+
export const enum TodoSliceEnum {
|
150
|
+
COMPLETE = 'Complete',
|
151
|
+
INCOMPLETE = 'Incomplete',
|
152
|
+
}
|
153
|
+
|
154
|
+
export class Todo {
|
155
|
+
constructor(
|
156
|
+
public complete: boolean,
|
157
|
+
public title: string,
|
158
|
+
public gid?: string,
|
159
|
+
public id?: string
|
160
|
+
) {}
|
161
|
+
}
|
162
|
+
|
163
|
+
export const extraTodo: Todo = new Todo(false, 'Do me later.');
|
164
|
+
|
165
|
+
export let todos = [
|
166
|
+
new Todo(false, 'You complete me!'),
|
167
|
+
new Todo(true, 'You completed me!'),
|
168
|
+
];
|
169
|
+
|
170
|
+
export function todosFactory(): Todo[] {
|
171
|
+
return [
|
172
|
+
new Todo(false, 'You complete me!'),
|
173
|
+
new Todo(true, 'You completed me!'),
|
174
|
+
];
|
175
|
+
}
|
176
|
+
|
177
|
+
export function todosClone(): Todo[] {
|
178
|
+
return todos.map((obj) => ({ ...obj }));
|
179
|
+
}
|
180
|
+
|
181
|
+
//============================================
|
182
|
+
// API: constructor()
|
183
|
+
//
|
184
|
+
// Create a Todo Entity Store
|
185
|
+
//============================================
|
186
|
+
let store: EStore<Todo> = new EStore<Todo>(todosFactory());
|
187
|
+
|
188
|
+
//============================================
|
189
|
+
// API: post, put, delete
|
190
|
+
//
|
191
|
+
// Perform post (Create), put (Update), and delete opeartions
|
192
|
+
// on the store.
|
193
|
+
//============================================
|
194
|
+
const todoLater: Todo = new Todo(false, 'Do me later.');
|
195
|
+
todoLater.id = 'findMe';
|
196
|
+
store.post(todoLater);
|
197
|
+
const postedTodo = store.findOneByID('findMe');
|
198
|
+
postedTodo.title = 'Do me sooner';
|
199
|
+
store.put(postedTodo);
|
200
|
+
store.delete(postedTodo);
|
201
|
+
|
202
|
+
//============================================
|
203
|
+
// API: allSnapshot()
|
204
|
+
//
|
205
|
+
// Take a snapshot of all the entities
|
206
|
+
// in the store
|
207
|
+
//============================================
|
208
|
+
let snapshot: Todo[] = store.allSnapshot();
|
209
|
+
|
210
|
+
//============================================
|
211
|
+
// API: obs
|
212
|
+
//
|
213
|
+
// Create a subscription to the entities in
|
214
|
+
// the store.
|
215
|
+
//============================================
|
216
|
+
let todosSubscription: Subscription = store.obs.subscribe((todos: Todo[]) => {
|
217
|
+
console.log(`The store todos ${todos}`);
|
218
|
+
});
|
219
|
+
|
220
|
+
//============================================
|
221
|
+
// API: findOne()
|
222
|
+
//
|
223
|
+
// Find a Todo instance using the
|
224
|
+
// Global ID (guid) property.
|
225
|
+
//============================================
|
226
|
+
const globalID: string = '1';
|
227
|
+
let findThisTodo = new Todo(false, 'Find this Todo', globalID);
|
228
|
+
|
229
|
+
store.post(findThisTodo);
|
132
230
|
|
231
|
+
const todo = store.findOne(globalID);
|
232
|
+
console.log(todo);
|
233
|
+
|
234
|
+
//============================================
|
235
|
+
// API: findOneByID()
|
236
|
+
//
|
237
|
+
// Find a Todo instance using the
|
238
|
+
// ID (id) property.
|
239
|
+
//============================================
|
240
|
+
const ID: string = 'id';
|
241
|
+
let todoWithID = new Todo(false, 'Find this Todo by ID');
|
242
|
+
todoWithID.id = ID;
|
243
|
+
|
244
|
+
store.post(todoWithID);
|
245
|
+
const todoFoundByID = store.findOneByID(ID);
|
246
|
+
|
247
|
+
console.log(`The Todo instance found by id is ${todoFoundByID}`);
|
248
|
+
|
249
|
+
//============================================
|
250
|
+
// API: observeLoading()
|
251
|
+
//
|
252
|
+
// Subscribe to the store loading indicator
|
253
|
+
// and toggle it to see the values change.
|
254
|
+
//============================================
|
255
|
+
store.observeLoading().subscribe((loading) => {
|
256
|
+
console.log(`Is data loading: ${loading}`);
|
257
|
+
});
|
258
|
+
store.loading = true;
|
259
|
+
store.loading = false;
|
260
|
+
|
261
|
+
//============================================
|
262
|
+
// API: observeSearching()
|
263
|
+
//
|
264
|
+
// Subscribe to the store searching indicator
|
265
|
+
// and toggle it to see the values change.
|
266
|
+
//============================================
|
267
|
+
store.observeSearching().subscribe((searching) => {
|
268
|
+
console.log(`Is the store searching: ${searching}`);
|
269
|
+
});
|
270
|
+
store.searching = true;
|
271
|
+
store.searching = false;
|
272
|
+
|
273
|
+
//============================================
|
274
|
+
// API: addActive()
|
275
|
+
// Perform active state tracking. Initially the
|
276
|
+
// number of active entities will be zero.
|
277
|
+
//============================================
|
278
|
+
console.log(`The number of active Todo instances is ${store.active.size}`);
|
279
|
+
let todo1: Todo = new Todo(false, 'The first Todo!', GUID());
|
280
|
+
let todo2: Todo = new Todo(false, 'The first Todo!', GUID());
|
281
|
+
store.addActive(todo1);
|
282
|
+
console.log(`The number of active Todo instances is ${store.active.size}`);
|
283
|
+
|
284
|
+
console.log(
|
285
|
+
`The number of active Todo instances by the activeSnapshot is ${
|
286
|
+
store.activeSnapshot().length
|
287
|
+
}`
|
288
|
+
);
|
289
|
+
|
290
|
+
//============================================
|
291
|
+
// API: observeActive()
|
292
|
+
//
|
293
|
+
// Subscribing to the observeActive() observable
|
294
|
+
// provides the map of active Todo instances.
|
295
|
+
//============================================
|
296
|
+
store.observeActive().subscribe((active) => {
|
297
|
+
console.log(`The active Todo instances are: ${active}`);
|
298
|
+
});
|
299
|
+
|
300
|
+
//============================================
|
301
|
+
// API: deleteActive()
|
302
|
+
// Delete the active Todo instance.
|
303
|
+
// This will set the number of active
|
304
|
+
// Todo instances back to zero.
|
305
|
+
//============================================
|
306
|
+
store.deleteActive(todo1);
|
307
|
+
console.log(
|
308
|
+
`The number of active Todo instances by the activeSnapshot is ${
|
309
|
+
store.activeSnapshot().length
|
310
|
+
}`
|
311
|
+
);
|
312
|
+
|
313
|
+
//============================================
|
314
|
+
// API: count()
|
315
|
+
//
|
316
|
+
// Dyanically count the Number of Entries in the Store.
|
317
|
+
//============================================
|
318
|
+
let countSubscription = store.count().subscribe((c) => {
|
319
|
+
console.log(`The number of Todo entities stored is ${c}`);
|
320
|
+
});
|
321
|
+
|
322
|
+
//============================================
|
323
|
+
// API: toggle()
|
324
|
+
//
|
325
|
+
// When we post another todo using toggle
|
326
|
+
// instance the subscribed to count
|
327
|
+
// dynamically increases by 1.
|
328
|
+
// When we call toggle again,
|
329
|
+
// removing the instance the
|
330
|
+
// count decreases by 1.
|
331
|
+
//============================================
|
332
|
+
store.toggle(extraTodo);
|
333
|
+
store.toggle(extraTodo);
|
334
|
+
|
335
|
+
//============================================
|
336
|
+
// API: contains()
|
337
|
+
//
|
338
|
+
// When we post another todo using toggle
|
339
|
+
// the store now contains it.
|
340
|
+
//============================================
|
341
|
+
console.log(
|
342
|
+
`Does the store contain the extraTodo ${store.contains(extraTodo)}`
|
343
|
+
);
|
344
|
+
store.toggle(extraTodo);
|
345
|
+
console.log(
|
346
|
+
`Does the store contain the extraTodo ${store.contains(extraTodo)}`
|
347
|
+
);
|
348
|
+
store.toggle(extraTodo);
|
349
|
+
console.log(
|
350
|
+
`Does the store contain the extraTodo ${store.contains(extraTodo)}`
|
351
|
+
);
|
352
|
+
|
353
|
+
//============================================
|
354
|
+
// API: containsbyID()
|
355
|
+
//
|
356
|
+
// When we post another todo using toggle
|
357
|
+
// the store now contains it.
|
358
|
+
//
|
359
|
+
// Note the containsByID() can be called with
|
360
|
+
// both the id property or the entire instance.
|
361
|
+
//============================================
|
362
|
+
let todoByID = new Todo(false, 'This is not in the store', undefined, '1');
|
363
|
+
store.post(todoByID);
|
364
|
+
console.log(
|
365
|
+
`Does the store contain the todoByID ${store.containsById(todoByID.id)}`
|
366
|
+
);
|
367
|
+
console.log(
|
368
|
+
`Does the store contain the todoByID ${store.containsById(todoByID)}`
|
369
|
+
);
|
370
|
+
store.toggle(todoByID);
|
371
|
+
console.log(
|
372
|
+
`Does the store contain the todoByID ${store.containsById(todoByID.id)}`
|
373
|
+
);
|
374
|
+
console.log(
|
375
|
+
`Does the store contain the todoByID ${store.containsById(todoByID)}`
|
376
|
+
);
|
377
|
+
|
378
|
+
//============================================
|
379
|
+
// API: equalsByGUID and equalsByID
|
380
|
+
//
|
381
|
+
// Compare entities by ID and Global ID (guid).
|
382
|
+
// We will assign the ID and the global ID
|
383
|
+
// instead of allowing the global ID to be
|
384
|
+
// assigned by the store on post.
|
385
|
+
//============================================
|
386
|
+
const guid = GUID();
|
387
|
+
let todoOrNotTodo1 = new Todo(false, 'Apples to Apples', guid, '1');
|
388
|
+
let todoOrNotTodo2 = new Todo(false, 'Apples to Apples', guid, '1');
|
389
|
+
|
390
|
+
const equalByID: boolean = store.equalsByID(todoOrNotTodo1, todoOrNotTodo2);
|
391
|
+
console.log(`Are the todos equal by id: ${equalByID}`);
|
392
|
+
const equalByGUID: boolean = store.equalsByGUID(todoOrNotTodo1, todoOrNotTodo2);
|
393
|
+
console.log(`Are the todos equal by global id: ${equalByGUID}`);
|
394
|
+
|
395
|
+
//============================================
|
396
|
+
// API: addSlice
|
397
|
+
//
|
398
|
+
// Add a slice for complete todo entities.
|
399
|
+
//
|
400
|
+
// We create a new store to demo with a
|
401
|
+
// consistent count.
|
402
|
+
//
|
403
|
+
// When posting the extraTodo which is
|
404
|
+
// incomplete, we see that the incomplete
|
405
|
+
// count increments.
|
406
|
+
//============================================
|
407
|
+
store.destroy();
|
408
|
+
store = new EStore<Todo>(todosFactory());
|
409
|
+
store.addSlice((todo) => todo.complete, TodoSliceEnum.COMPLETE);
|
410
|
+
store.addSlice((todo) => !todo.complete, TodoSliceEnum.INCOMPLETE);
|
411
|
+
const completeSlice = store.getSlice(TodoSliceEnum.COMPLETE);
|
412
|
+
const incompleteSlice = store.getSlice(TodoSliceEnum.INCOMPLETE);
|
413
|
+
completeSlice.count().subscribe((c) => {
|
414
|
+
console.log(`The number of entries in the complete slice is ${c}`);
|
415
|
+
});
|
416
|
+
incompleteSlice.count().subscribe((c) => {
|
417
|
+
console.log(`The number of entries in the incomplete slice is ${c}`);
|
418
|
+
});
|
419
|
+
store.post(extraTodo);
|
420
|
+
const incompleteTodos: Todo[] = incompleteSlice.allSnapshot();
|
421
|
+
console.log(`The incomplete Todo entities are ${incompleteTodos}`);
|
422
|
+
|
423
|
+
//============================================
|
424
|
+
// API: isEmpty()
|
425
|
+
//
|
426
|
+
// Check whether the store is empty.
|
427
|
+
//============================================
|
428
|
+
store.isEmpty().subscribe((empty) => {
|
429
|
+
console.log(`Is the store empty? ${empty}`);
|
430
|
+
});
|
431
|
+
```
|
432
|
+
|
433
|
+
## Features
|
434
|
+
|
435
|
+
- Live Stackblitz demoes
|
436
|
+
- [Typedoc with inlined examples](https://fireflysemantics.github.io/slice/doc/)
|
437
|
+
- [Well documented test cases run with Jest - Each file has a corresponding `.spec` file](https://github.com/fireflysemantics/slice/tree/master/src)
|
438
|
+
- Stream both Entity and Object Stores for UI Updates via RxJS
|
439
|
+
- Define entities using Typescript classes, interfaces, or types
|
440
|
+
- [Active state tracking](https://medium.com/@ole.ersoy/monitoring-the-currently-active-entity-with-slice-ff7c9b7826e8)
|
441
|
+
- [Supports for Optimistic User Interfaces](https://medium.com/@ole.ersoy/optimistic-user-identity-management-with-slice-a2b66efe780c)
|
442
|
+
- RESTful API for performing CRUD operations that stream both full and delta updates
|
443
|
+
- Dynamic creation of both object and entity stores
|
444
|
+
- Observable delta updates for Entities
|
445
|
+
- Real time application of Slice `Predicate<E>` filtering that is `Observable`
|
446
|
+
- `Predicate` based snapshots of entities
|
447
|
+
- Observable `count` of entities in the entity store. The `count` feature can also be `Predicate` filtered.
|
448
|
+
- Configurable global id (Client side id - `gid`) and server id (`id`) id property names for entities.
|
449
|
+
- The stream of entities can be sorted via an optional boolean expression passed to `observe`.
|
133
450
|
|
134
451
|
# Firefly Semantics Slice Development Center Media and Documentation
|
135
452
|
|
@@ -193,7 +510,7 @@ console.log(`The snapshot is ${OS.snapshot(OS.S.K1)}`);
|
|
193
510
|
|
194
511
|
# API Documentation
|
195
512
|
|
196
|
-
See [Typedoc API Documentation](https://fireflysemantics.github.io/slice/
|
513
|
+
See [Typedoc API Documentation](https://fireflysemantics.github.io/slice/typedoc/)
|
197
514
|
|
198
515
|
The documentation for the API includes simple examples of how to apply the API to a use case.
|
199
516
|
|
@@ -221,26 +538,9 @@ Run `npm run c` to build the project. The build artifacts will be stored in the
|
|
221
538
|
|
222
539
|
## Running unit tests
|
223
540
|
|
224
|
-
Run `
|
225
|
-
|
541
|
+
Run `npm run test` to execute the unit tests via [Jest](https://jestjs.io/).
|
226
542
|
|
227
|
-
## Features
|
228
543
|
|
229
|
-
- Live Stackblitz demoes
|
230
|
-
- [Typedoc with inlined examples](https://fireflysemantics.github.io/slice/doc/)
|
231
|
-
- [Well documented test cases run with Jest - Each file has a corresponding `.spec` file](https://github.com/fireflysemantics/slice/tree/master/src)
|
232
|
-
- Stream both Entity and Object Stores for UI Updates via RxJS
|
233
|
-
- Define entities using Typescript classes, interfaces, or types
|
234
|
-
- [Active state tracking](https://medium.com/@ole.ersoy/monitoring-the-currently-active-entity-with-slice-ff7c9b7826e8)
|
235
|
-
- [Supports for Optimistic User Interfaces](https://medium.com/@ole.ersoy/optimistic-user-identity-management-with-slice-a2b66efe780c)
|
236
|
-
- RESTful API for performing CRUD operations that stream both full and delta updates
|
237
|
-
- Dynamic creation of both object and entity stores
|
238
|
-
- Observable delta updates for Entities
|
239
|
-
- Real time application of Slice `Predicate<E>` filtering that is `Observable`
|
240
|
-
- `Predicate` based snapshots of entities
|
241
|
-
- Observable `count` of entities in the entity store. The `count` feature can also be `Predicate` filtered.
|
242
|
-
- Configurable global id (Client side id - `gid`) and server id (`id`) id property names for entities.
|
243
|
-
- The stream of entities can be sorted via an optional boolean expression passed to `observe`.
|
244
544
|
|
245
545
|
## Tests
|
246
546
|
|