XO Wallet Integration Part IV
This commit is contained in:
@@ -23,18 +23,22 @@ export interface Activity {
|
||||
}
|
||||
|
||||
// Define the snapshot structure
|
||||
export type SnapshotByType = {
|
||||
[type: string]: {
|
||||
export type SnapshotState = {
|
||||
[key: string]: {
|
||||
[entityId: string]: Activity;
|
||||
};
|
||||
};
|
||||
|
||||
export type ActivitiesIndexedByKey<T extends Activity = Activity> = {
|
||||
[entityId: string]: T;
|
||||
export type SnapshotData<T extends Activity = Activity> = {
|
||||
[keyOrEntityId: string]: T;
|
||||
};
|
||||
|
||||
export type ActivitiesIndexedByEntityId<T extends Activity = Activity> = {
|
||||
[key: string]: T;
|
||||
export type SnapshotIndexedByKey<T extends Activity = Activity> = {
|
||||
[key: string]: { [entityId: string]: T };
|
||||
};
|
||||
|
||||
export type SnapshotIndexedByEntityId<T extends Activity = Activity> = {
|
||||
[entityId: string]: { [key: string]: T };
|
||||
};
|
||||
|
||||
// Policy type definition
|
||||
@@ -45,6 +49,7 @@ export type PolicyFunction = (
|
||||
|
||||
export type ActivitiesEvents = {
|
||||
snapshotUpdated: undefined;
|
||||
updated: { activity: Activity };
|
||||
[key: `updated:${string}`]: { activity: Activity };
|
||||
};
|
||||
|
||||
@@ -79,9 +84,15 @@ export class Activities extends EventEmitter<ActivitiesEvents> {
|
||||
// TODO: If you can refactor this around your new Storage mechanism, things become a lot simpler:
|
||||
// 1. You don't need to define such a clunky snapshot format because you have indexes.
|
||||
// 2. Caching of snapshots likely becomes possible (because you can use a storage adapter).
|
||||
public snapshot: SnapshotByType = {};
|
||||
private policies = new Map<string, PolicyFunction>();
|
||||
private storeKeyMap = new Map<string, string>();
|
||||
public snapshot: SnapshotState = {};
|
||||
|
||||
// Indexes.
|
||||
// TODO: We want to be able to remove these in favor of the TODO note above.
|
||||
// public snapshotIndexedByEntity: SnapshotIndexedByEntityId = {};
|
||||
// public snapshotIndexedByKey: SnapshotIndexedByKey = {};
|
||||
|
||||
protected policies = new Map<string, PolicyFunction>();
|
||||
protected storeKeyMap = new Map<string, string>();
|
||||
|
||||
/**
|
||||
* Create an Activities instance from the given composite store.
|
||||
@@ -93,7 +104,7 @@ export class Activities extends EventEmitter<ActivitiesEvents> {
|
||||
return activities;
|
||||
}
|
||||
|
||||
private constructor(store: StoreComposite) {
|
||||
protected constructor(store: StoreComposite) {
|
||||
super();
|
||||
|
||||
// Assign our dependencies.
|
||||
@@ -167,6 +178,10 @@ export class Activities extends EventEmitter<ActivitiesEvents> {
|
||||
return removedActivity;
|
||||
}
|
||||
|
||||
public getSnapshot() {
|
||||
return this.snapshot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific activity by type and id with type inference
|
||||
*/
|
||||
@@ -178,12 +193,23 @@ export class Activities extends EventEmitter<ActivitiesEvents> {
|
||||
return activity as T | undefined;
|
||||
}
|
||||
|
||||
public getByEntity(entityId: string = '') {
|
||||
return Object.keys(this.snapshot).reduce(
|
||||
(result, key) => {
|
||||
const activity = this.snapshot[key][entityId];
|
||||
if (activity) {
|
||||
result[key] = activity;
|
||||
}
|
||||
return result;
|
||||
},
|
||||
{} as Record<string, Activity>,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all activities of a specific type
|
||||
*/
|
||||
public getByKey<T extends Activity>(
|
||||
key: T['key'],
|
||||
): ActivitiesIndexedByKey<T> {
|
||||
public getByKey<T extends Activity>(key: T['key']): SnapshotData<T> {
|
||||
const activities = this.snapshot[key];
|
||||
if (!activities) {
|
||||
return {};
|
||||
@@ -191,9 +217,25 @@ export class Activities extends EventEmitter<ActivitiesEvents> {
|
||||
|
||||
// NOTE: We want to return a new object, not a reference to our current object.
|
||||
// But we only need to "clone" the first level as each activity itself is immutable.
|
||||
return { ...activities } as ActivitiesIndexedByKey<T>;
|
||||
return { ...activities } as SnapshotData<T>;
|
||||
}
|
||||
|
||||
/*
|
||||
public getByEntityId<T extends Activity>(
|
||||
entityId: string = '',
|
||||
): SnapshotData<T> {
|
||||
const activities = this.snapshotIndexedByEntity[entityId];
|
||||
|
||||
if (!activities) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// NOTE: We want to return a new object, not a reference to our current object.
|
||||
// But we only need to "clone" the first level as each activity itself is immutable.
|
||||
return { ...activities } as SnapshotData<T>;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Register a policy for handling conflicts between activities of the same type
|
||||
* @param type Activity type to register policy for
|
||||
@@ -239,6 +281,9 @@ export class Activities extends EventEmitter<ActivitiesEvents> {
|
||||
}
|
||||
this.storeKeyMap.set(snapshotKey, storeKey);
|
||||
|
||||
// Emit the updated activity.
|
||||
this.emit('updated', { activity });
|
||||
|
||||
// Emit the updated activity.
|
||||
this.emit(`updated:${activity.key}`, { activity });
|
||||
|
||||
@@ -254,7 +299,7 @@ export class Activities extends EventEmitter<ActivitiesEvents> {
|
||||
* Compile a full snapshot from scratch
|
||||
* This happens automatically on initialization
|
||||
*/
|
||||
private async compileSnapshot(): Promise<SnapshotByType> {
|
||||
private async compileSnapshot(): Promise<SnapshotState> {
|
||||
// Clear existing snapshot
|
||||
this.snapshot = {};
|
||||
this.storeKeyMap.clear();
|
||||
@@ -297,11 +342,33 @@ export class Activities extends EventEmitter<ActivitiesEvents> {
|
||||
* Set an activity in the snapshot, creating necessary object structure
|
||||
*/
|
||||
private setActivityInSnapshot(activity: Activity): void {
|
||||
if (!this.snapshot[activity.key]) {
|
||||
this.snapshot[activity.key] = {};
|
||||
// Assign the key for convenience.
|
||||
const key = activity.key;
|
||||
|
||||
// Assign the entityId to the provided entityId - or to the root ("") entity if none provided.
|
||||
const entityId = activity.entityId || '';
|
||||
|
||||
if (!this.snapshot[key]) {
|
||||
this.snapshot[key] = {};
|
||||
}
|
||||
|
||||
this.snapshot[activity.key][activity.entityId || ''] = activity;
|
||||
this.snapshot[key][entityId] = activity;
|
||||
|
||||
/*
|
||||
// Index the activity by entityId:key.
|
||||
if (!this.snapshotIndexedByEntity[entityId]) {
|
||||
this.snapshot[entityId] = {};
|
||||
}
|
||||
|
||||
this.snapshotIndexedByEntity[entityId][key] = activity;
|
||||
|
||||
// Index the activity by key:entityId.
|
||||
if (!this.snapshotIndexedByKey[key]) {
|
||||
this.snapshot[key] = {};
|
||||
}
|
||||
|
||||
this.snapshotIndexedByKey[key][entityId] = activity;
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user