Skip to content
Egor Grushin edited this page Nov 1, 2020 · 15 revisions

Type reference

This is the main class that you will use to manipulate and store entity's instances. It has next members:

actionCreators: EntityActionCreators<T> - this is all redux action creators that entity uses. It will help you in cases when you need to perform actions manually and explicit. In 99.99% cases you won't need it.

Get methods:

getLoadingState$(): Observable<LoadingState | undefined>

It returns observable that will listen to the full entity loading state. LoadingState for entity is changed for every action that runs remote action.

getLoadingStateById$(
    id: Id,
    isAsap?: boolean,
): Observable<LoadingState | undefined>;

It returns observable that will listen to the entity by id loading state. LoadingState by id is changed for related to the id actions that runs remote action. isAsap flag will set scheduler for this observable to asapScheduler.

getLoadingStateByIds$(
    ids: Id[],
    isAsap?: boolean,
): Observable<LoadingState | undefined>;

It returns observable that will listen to the entity by ids loading state. isAsap flag will set scheduler for this observable to asapScheduler.

It will combine loading states by ids into LoadingState follow the next rule:

  • if any LoadingState.isLoading -> result LoadingState.isLoading will be true

  • if any LoadingState.error -> result LoadingState.error will be the first error

    More explicit algorithm here

getPage$(
    config: unknown,
    isAsap?: boolean,
): Observable<Page | undefined>;

It returns observable that will listen to Entity page stored under key equal hash of config. isAsap flag will set scheduler for this observable to asapScheduler.

getPageLoadingState$(
    config: unknown,
    isAsap?: boolean,
): Observable<LoadingState | undefined>;

It returns observable that will listen to Entity page loading state stored under key equal hash of config. isAsap flag will set scheduler for this observable to asapScheduler.

getAll$(): Observable<T[] | undefined>;

It returns observable that will listen to all entity's instances.

getPages$(): Observable<Page[]>;

It returns observable that will listen to all entity pages stored by any config's hashes.

Dispatch methods:

add(
    data: T,
    config?: unknown,
    options?: EntityAddOptions,
): EntityActions;

This method will dispatch an action that will store data object as entity instance. If config passed, it will assotiate this instance with config's hash page. It also accepts options:

data: T - [required] this item preprocessed by Entity.schema.id function if it exists will be stored under config's hash.

config: unknown - [optional] [default: undefined] this config (even if it equals undefined) will be hashed by Entity.schema.hashFn and this hash will be used as page key where will be stored data.

options: EntityAddOptions - [optional]:

  • pasteIndex: number - [optional] [default: undefined] the index where new instance will be stored. By default it will be stored at last

  • merge: boolean - [optional] [default: true] whether to merge entity isntance if there is instance with the same id. Merge is perfromed by merge util.

addWithId(
    data: T,
    tempId: string,
    config?: unknown,
    options?: EntityAddOptions,
): EntityActions;

The same as add but you can use tempId for create an entity instance (or update existing) via apply patch (read more in optimistic change section).

addList(
    data: T[],
    config?: unknown,
    isReplace?: boolean,
    hasMore?: boolean,
    options?: EntityAddListOptions,
): EntityActions;

This method the same as add but it works with an array of entity's instances.

data: T[] - [required] this items preprocessed by Entity.schema.id function if it exists will be stored under config's hash.

config: unknown - [optional] [default: undefined] this config (even if it equals undefined) will be hashed by Entity.schema.hashFn and this hash will be used as page key where will be stored data.

isReplace: boolean - [optional] [default: false] whether to replace instances previouslyloaded and stored under config's hash.

hasMore: boolean - [optional] [default: false] whether to set hasMore flag and do not load entities using get$ with the same config.

options: EntityAddListOptions - [optional]:

  • pasteIndex: number - [optional] [default: undefined] an index from where new instance will be stored. By default it will be stored from the last

  • merge: boolean - [optional] [default: true] whether to merge entity isntances if there is instances with the same id. Merge is perfromed by merge util.

change(
    id: Id,
    patch: PatchRequest<T>,
    options?: ChangeOptions,
): EntityActions;

This method will dispatch an action that will change entity's instance by id using patch.

id: Id - [required] an id of changing entity's instance.

patch: PatchRequest<T> - [required] a patch to apply. It can be either deep partial object of T, or a function that will accept previous value from store and return a deep partial object of T.

options: ChangeOptions - [optional]:

  • merge: boolean - [optional] [default: true] whether to merge patch with exist entity or to replace it with patch. Merge is perfromed by merge util.
  • ifNotExist: boolean - [optional] [default: false] to create an entity if no entity with given id exists

changeList(
    patches: IdPatchRequest<T>[],
    options?: ChangeOptions,
): EntityActions;

This method the same as change but it works with an array of patches.

patches: IdPatchRequest<T>[] - [required] this is array of object with id and patch from change method description.

options: ChangeOptions - [optional]:

  • merge: boolean - [optional] [default: true] whether to merge patch with exist entity or to replace it with the patch. Merge is performed by merge util.
  • ifNotExist: boolean - [optional] [default: false] to create an entity if no entity with given id exists

remove(
    id: Id,
    options?: EntityRemoveOptions,
): EntityActions;

This method will dispatch an action that will be remove entity's instance with given id.

options: EntityRemoveOptions - [optional]

  • safe: boolean - [optional] [default: false] whether to permamenty remove entity's instance. If true is passed, it will just mark entity's instance as removed and it won't be visible by select observables (listened above) until it will be restored by restoreRemoved.

restoreRemoved(
    id: Id,
): EntityActions;

This method will dispatch an action that will be restore entity's instance with given id that was marked as removed using either removeRemote$ or removeListRemote$ or remove or removeList methods with options.safe = true.

removeList(
    ids: Id[],
    options?: EntityRemoveListOptions,
): EntityActions;

This method will dispatch an action that will be remove entities' instances with given ids.

options: EntityRemoveListOptions - [optional]

  • safe: boolean - [optional] [default: false] whether to permamenty remove entity's instance. If true is passed, it will just mark entity's instance as removed and it won't be visible by select observables (listened above) until it will be restored by restoreRemovedList.

restoreRemovedList(
    ids: Id[],
): EntityActions;

This method will dispatch an action that will be restore entities' instances with given ids that was marked as removedusing either removeRemote$ or removeListRemote$ or remove or removeList methods with options.safe = true.

setLoadingState(
    state: LoadingState,
    config?: unknown,
    options?: EntitySetLoadingStateOptions,
): EntityActions;

This will dispatch an action and store new loading state.

state: LoadingState - [required] loading state to store

config: unknown - [optional] config that will be hashed and used to set loading state for related page

options: EntitySetLoadingStateOptions - [optional] - no options is now available

clear(config: unknown): EntityActions;

This will dispatch an action that will be clear page's instances

config: unknown - [required] the config that will be hashed and used to clear the related page.

clearAll(): EntityActions;

This will dispatch an action that will be clear all pages with theirs instances.

setLoadingStateById(
    id: Id,
    state: LoadingState,
    options?: EntitySetLoadingStateOptions,
): EntityActions;

This will dispatch an action and store new loading state for the id.

id: Id - [required] the id to state associated with.

state: LoadingState - [required] loading state to store

options: EntitySetLoadingStateOptions - [optional] - no options is now available

setLoadingStateByIds(
    ids: Id[],
    state: LoadingState,
    options?: EntitySetLoadingStateOptions,
): EntityActions;

This will dispatch an action and store the same loading state for each id in ids.

ids: Id[] - [required] the ids to state associated with.

state: LoadingState - [required] loading state to store

options: EntitySetLoadingStateOptions - [optional] - no options is now available

setLoadingStateForKey(
    id: Id,
    key: string,
    state: LoadingState,
    options?: EntitySetLoadingStateOptions,
): EntityActions;

This will dispatch an action and store new loading state for the id for the key.

id: Id - [required] the id to state associated with.

key: string - [required] the key to state associated with.

state: LoadingState - [required] loading state to store

options: EntitySetLoadingStateOptions - [optional] - no options is now available

setLoadingStateBus(
    state: LoadingState,
    id?: Id,
    config?: unknown,
    key?: string,
): EntityActions;

This will call either setLoadingStateById or setLoadingStateByIds or setLoadingStateForKey based on arguments

batch(
    actions: EntityActions[],
): EntityActions;

This method allows you to dispatch several actions manually and explicit.

affectLoadingState(
    config?: unknown,
    key?: string,
    rethrow?: boolean,
): AffectLoadingStateFactory;

It returns AffectLoadingStateFactory for page loading state based on config and key. More detailed here.

affectLoadingStateById(
    id?: Id,
    key?: string,
    rethrow?: boolean,
): AffectLoadingStateFactory;

It returns AffectLoadingStateFactory for entity's instance loading state based on id and key. More detailed here.

affectLoadingStateByConfigOrId(
    config?: unknown,
    id?: Id,
    key?: string,
    rethrow?: boolean,
): AffectLoadingStateFactory;

It returns AffectLoadingStateFactory and uses setLoadingStateBus under hood to determine loading state setter.

Mixed methods (Get + Dispatch methods combinations):

 loadList$(
        config: unknown,
        dataSource: Observable<ResponseArray<T>> | Response$Factory<T>,
        options?: EntityLoadListOptions,
        paginatorSubj?: BehaviorSubject<boolean>,
    ): Observable<PaginatedResponse<T>>;

This method will subscribe to dataSource and store the result using addList method. It will also affect loading state using setLoadingStateBus. This method returns cold observable.

config: unknown - [required] the config that will be hashed and used as key for getting related page and check its hasMore param to decide wheter to run dataSource. It also set loading state for this page. It also store result to this page.

dataSource: Observable<ResponseArray<T>> | Response$Factory<T> - [required] the main source of data. It can be either Observable with entity's instances or a factory to be used with paginatorSubj

options?: EntityLoadListOptions - [optional]

  • pasteIndex: number - [optional] [default: undefined] the index where new instances will be stored. By default it will be stored at last
  • merge: boolean - [optional] [default: true] whether to merge entity isntance if there is instance with the same id. Merge is perfromed by merge util.
  • single: boolean - [optional] [default: false] if passed true it will never subscribe to dataSource if under config's hash page there are entity instances already
  • rethrow: boolean - [optional] [default: false] whether to rethrow dataSource Observable error. Caution if true is passed it will be tear down Subscription in case of error
  • pageSize: number - [optional] [default: Entity.schema.pageSize] the page size that will be used in dataSource if it is factory

paginatorSubj: BehaviorSubject<boolean> - [optional] [default: new BehaviorSubject(false)] pagination subject that allows you to either request next page, or refresh (clear all and request first page).

    loadById$(
        id: Id,
        dataSource$: Observable<T>,
        options?: EntityLoadOptions,
    ): Observable<T>;

This method will subscribe to dataSource and store the result using add method. It will also affect loading state using setLoadingStateBus. This method returns cold observable.

id: Id - [required] an id of entity instance to store by

dataSource: Observable<T> - [required] the main source of data.

options?: EntityLoadOptions - [optional]

  • rethrow: boolean - [optional] [default: false] whether to rethrow dataSource Observable error. Caution if true is passed it will be tear down Subscription in case of error

    get$(
        config: unknown,
        dataSource?: Observable<ResponseArray<T>> | Response$Factory<T>,
        options?: EntityGetListOptions,
        paginatorSubj?: BehaviorSubject<boolean>,
    ): Observable<T[] | undefined>;

This method is the most complex method of the library. It follows next steps:

  1. It reserves place in store and places with key equals config's hash using Entity.schema.hashFn
  2. It creates selector for reserved place in store
  3. It immediately return an Observable that listen to reserved place using selector. It means you will get:
    1. undefined in case of new config's hash
    2. previously stored array of entities associated with given config
    3. updated array of entities, which will be resolving from next steps (TL;DR: entities will be resolved from dataSource)
  4. It sets loadingState (will be described later) to { isLoading: true, error: null }
  5. It subscribes to given dataSource
  6. When given dataSource emits value, Entity will store this result at reserved place.
  7. It sets loadingState to { isLoading: false, error: null }
  8. In case of error from given dataSource Entity will set loadingState to { isLoading: false, error: <error from dataSource.error> }
  9. It will emit updated array
  10. From this point, returned Observable will emit actual entity array if it is changed from other places even if some entity is changed by its id using change

The algorithm you can always see in Redux DevTools panel. Also the method is the most used method.

config: unknown - [required] the config that will be hashed and used as key for getting related page and check its hasMore param to decide wheter to run dataSource. It also set loading state for this page. It also store result to this page.

dataSource: Observable<ResponseArray<T>> | Response$Factory<T> - [required] the main source of data. It can be either Observable with entity's instances or a factory to be used with paginatorSubj

options?: EntityGetListOptions - [optional]

  • pasteIndex: number - [optional] [default: undefined] the index where new instances will be stored. By default it will be stored at last
  • merge: boolean - [optional] [default: true] whether to merge entity isntance if there is instance with the same id. Merge is perfromed by merge util.
  • single: boolean - [optional] [default: false] if passed true it will never subscribe to dataSource if under config's hash page there are entity instances already
  • rethrow: boolean - [optional] [default: false] whether to rethrow dataSource Observable error. Caution if true is passed it will be tear down Subscription in case of error
  • pageSize: number - [optional] [default: Entity.schema.pageSize] the page size that will be used in dataSource if it is factory

paginatorSubj: BehaviorSubject<boolean> - [optional] [default: new BehaviorSubject(false)] pagination subject that allows you to either request next page, or refresh (clear all and request first page).

    getDictionary$(
        config: unknown,
        dataSource?: Observable<ResponseArray<T>> | Response$Factory<T>,
        options?: EntityGetListOptions,
        paginatorSubj?: BehaviorSubject<boolean>,
    ): Observable<Dictionary<T>>;

This method is the same as get$ but it returns a dictionary of page instances (9 point in get$ algorithm).

    getById$(
        id: Id,
        dataSource$?: Observable<T>,
        options?: EntityGetOptions,
    ): Observable<T | undefined>;

This method is the same as get$ but it works with only one entity instance by id

    addRemote$(
        entity: T,
        config: unknown,
        dataSource$: Observable<T>,
        options?: EntityAddOptions,
    ): Observable<T>;

This method will subscribe to dataSource$ and store the result using add method. It will also affect loading state using setLoadingStateBus. This method returns cold observable.

entity: T - [required] an instance to store if options.optimistic equals true. In basic cases you have to pass undefined and the instance will be recieved from dataSource$

config: unknown - [optional] [default: undefined] this config (even if it equals undefined) will be hashed by Entity.schema.hashFn and this hash will be used as page key where will be stored entity's instance.

dataSource$: Observable<T> - [required] the main source of entity's instance.

options?: EntityAddOptions - [optional]

  • pasteIndex: number - [optional] [default: undefined] the index where new instances will be stored. By default it will be stored at last
  • merge: boolean - [optional] [default: true] whether to merge entity isntance if there is instance with the same id. Merge is perfromed by merge util.

  • single: boolean - [optional] [default: false] if passed true it will never subscribe to dataSource if under config's hash page there are entity instances already

  • rethrow: boolean - [optional] [default: false] whether to rethrow dataSource Observable error. Caution if true is passed it will be tear down Subscription in case of error

  • optimistic: boolean - [optional] [default: false] whether to use optimistic strategy. More detailed here

    changeRemote$(
        id: Id,
        patch: PatchRequest<T>,
        dataSource$: Observable<DeepPartial<T> | undefined>,
        options?: ChangeOptions,
    ): Observable<DeepPartial<T> | undefined>;

This method will subscribe to dataSource$ and apply patch using change method. It will also affect loading state using setLoadingStateBus. This method returns cold observable.

patch: PatchRequest<T> - [required] the patch to apply. It can be either deep partial object of T, or a function that will accept previous value from store and return a deep partial object of T.

This patch will be used if options.optimistic equals true. In basic cases you have to pass undefined and the patch will be recieved from dataSource$

dataSource$: Observable<T> - [required] the source of patch.

options: ChangeOptions - [optional]:

  • merge: boolean - [optional] [default: true] whether to merge patch with exist entity or to replace it with patch. whether to merge entity isntances if there is instances with the same id. Merge is perfromed by merge util.
  • ifNotExist: boolean - [optional] [default: false] to create an entity if no entity with given id exists
  • optimistic: boolean - [optional] [default: false] whether to use optimistic strategy. More detailed here

    changeListRemote$(
        patches: IdPatchRequest<T>[],
        dataSource$: Observable<IdPatch<T>[] | undefined>,
        options?: ChangeOptions,
    ): Observable<IdPatch<T>[] | undefined>;

This method will subscribe to dataSource$ and apply patches using changeList method. It will also affect loading state using setLoadingStateBus. This method returns cold observable.

patches: IdPatchRequest<T>[] - [required] this is array of object with id and patch from change method description.

This patch will be used if options.optimistic equals true. In basic cases you have to pass undefined and the patch will be recieved from dataSource$

dataSource$: Observable<T> - [required] the source of patch.

options: ChangeOptions - [optional]:

  • merge: boolean - [optional] [default: true] whether to merge patch with exist entity or to replace it with patch. whether to merge entity isntances if there is instances with the same id. Merge is perfromed by merge util.
  • ifNotExist: boolean - [optional] [default: false] to create an entity if no entity with given id exists
  • optimistic: boolean - [optional] [default: false] whether to use optimistic strategy. More detailed here

    removeRemote$<R>(
        id: Id,
        observable$: Observable<R>,
        options?: EntityRemoveOptions,
    ): Observable<R>;

This method will subscribe to observable$ and remove entity's instance using remove method. It will also affect loading state using setLoadingStateBus. This method returns cold observable.

observable$: Observable<R> - [required] observable to subscribe and remove on next

options: EntityRemoveOptions - [optional]

  • safe: boolean - [optional] [default: false] whether to permamenty remove entity's instance. If true is passed, it will just mark entity's instance as removed and it won't be visible by select observables (listened above) until it will be restored by restoreRemoved.
  • optimistic: boolean - [optional] [default: false] whether to use optimistic strategy. More detailed here

    removeListRemote$<R>(
        ids: Id[],
        observable$: Observable<R>,
        options?: EntityRemoveListOptions,
    ): Observable<R>;

This method will subscribe to observable$ and remove entities' instances using removeList method. It will also affect loading state using setLoadingStateBus. This method returns cold observable.

observable$: Observable<R> - [required] observable to subscribe and remove on next

options: EntityRemoveListOptions - [optional]

  • safe: boolean - [optional] [default: false] whether to permamenty remove entity's instance. If true is passed, it will just mark entity's instance as removed and it won't be visible by select observables (listened above) until it will be restored by restoreRemovedList.
  • optimistic: boolean - [optional] [default: false] whether to use optimistic strategy. More detailed here
Clone this wiki locally