@astral/mobx-query 1.4.0 → 1.6.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/AdaptableMap/AdaptableMap.d.ts +29 -0
- package/AdaptableMap/AdaptableMap.js +77 -0
- package/AdaptableMap/index.d.ts +1 -0
- package/AdaptableMap/index.js +1 -0
- package/AuxiliaryQuery/AuxiliaryQuery.d.ts +25 -26
- package/AuxiliaryQuery/AuxiliaryQuery.js +59 -34
- package/DataStorage/DataStorage.d.ts +11 -14
- package/DataStorage/DataStorage.js +12 -18
- package/InfiniteQuery/InfiniteQuery.d.ts +50 -55
- package/InfiniteQuery/InfiniteQuery.js +34 -57
- package/MobxQuery/MobxQuery.d.ts +48 -22
- package/MobxQuery/MobxQuery.js +88 -51
- package/Mutation/Mutation.d.ts +11 -34
- package/Mutation/Mutation.js +11 -38
- package/Query/Query.d.ts +45 -50
- package/Query/Query.js +28 -53
- package/QueryContainer/QueryContainer.d.ts +61 -0
- package/QueryContainer/QueryContainer.js +79 -0
- package/QueryContainer/index.d.ts +1 -0
- package/QueryContainer/index.js +1 -0
- package/README.md +25 -0
- package/StatusStorage/StatusStorage.d.ts +24 -0
- package/StatusStorage/StatusStorage.js +36 -0
- package/StatusStorage/index.d.ts +1 -0
- package/StatusStorage/index.js +1 -0
- package/StorageFactory/StorageFactory.d.ts +9 -0
- package/StorageFactory/StorageFactory.js +19 -0
- package/StorageFactory/index.d.ts +1 -0
- package/StorageFactory/index.js +1 -0
- package/package.json +1 -1
- package/types.d.ts +12 -12
package/Mutation/Mutation.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { action, makeObservable } from 'mobx';
|
|
2
2
|
import { AuxiliaryQuery } from '../AuxiliaryQuery';
|
|
3
|
+
import { QueryContainer } from '../QueryContainer';
|
|
4
|
+
import { StatusStorage } from '../StatusStorage';
|
|
3
5
|
/**
|
|
4
|
-
*
|
|
6
|
+
* Простой квери для запросов, которые не требуют кэширования,
|
|
5
7
|
* пример - POST запросы
|
|
6
8
|
*/
|
|
7
|
-
export class Mutation {
|
|
9
|
+
export class Mutation extends QueryContainer {
|
|
8
10
|
constructor(executor, { onError } = {}) {
|
|
11
|
+
const statusStorage = new StatusStorage();
|
|
12
|
+
super(statusStorage, null, new AuxiliaryQuery(statusStorage, null));
|
|
13
|
+
this.executor = executor;
|
|
9
14
|
/**
|
|
10
|
-
*
|
|
11
|
-
*/
|
|
12
|
-
this.auxiliary = new AuxiliaryQuery();
|
|
13
|
-
/**
|
|
14
|
-
* @description синхронный метод получения/отправки данных
|
|
15
|
+
* Синхронный метод получения/отправки данных
|
|
15
16
|
*/
|
|
16
17
|
this.sync = (options) => {
|
|
17
18
|
const { onSuccess, onError, params } = options || {};
|
|
@@ -31,41 +32,13 @@ export class Mutation {
|
|
|
31
32
|
});
|
|
32
33
|
};
|
|
33
34
|
/**
|
|
34
|
-
*
|
|
35
|
+
* Асинхронный метод получения/отправки данных,
|
|
35
36
|
* предполагается, что нужно будет самостоятельно обрабатывать ошибку
|
|
36
37
|
*/
|
|
37
38
|
this.async = (params) => {
|
|
38
39
|
return this.auxiliary.getUnifiedPromise(() => this.executor(params));
|
|
39
40
|
};
|
|
40
|
-
this.executor = executor;
|
|
41
41
|
this.defaultOnError = onError;
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* @description флаг загрузки данных
|
|
46
|
-
*/
|
|
47
|
-
get isLoading() {
|
|
48
|
-
return this.auxiliary.isLoading;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* @description флаг обозначающий, что последний запрос был зафейлен
|
|
52
|
-
*/
|
|
53
|
-
get isError() {
|
|
54
|
-
return this.auxiliary.isError;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* @description данные о последней ошибке
|
|
58
|
-
*/
|
|
59
|
-
get error() {
|
|
60
|
-
return this.auxiliary.error;
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* @description флаг обозначающий, что последний запрос был успешно завершен
|
|
64
|
-
*/
|
|
65
|
-
get isSuccess() {
|
|
66
|
-
return this.auxiliary.isSuccess;
|
|
67
|
-
}
|
|
68
|
-
get isIdle() {
|
|
69
|
-
return this.auxiliary.isIdle;
|
|
42
|
+
makeObservable(this, { async: action, sync: action });
|
|
70
43
|
}
|
|
71
44
|
}
|
package/Query/Query.d.ts
CHANGED
|
@@ -1,108 +1,103 @@
|
|
|
1
|
+
import { AuxiliaryQuery } from '../AuxiliaryQuery';
|
|
1
2
|
import type { FetchPolicy, QueryBaseActions, Sync, SyncParams } from '../types';
|
|
2
3
|
import type { DataStorage } from '../DataStorage';
|
|
4
|
+
import { QueryContainer } from '../QueryContainer';
|
|
5
|
+
import { type StatusStorage } from '../StatusStorage';
|
|
3
6
|
/**
|
|
4
|
-
*
|
|
7
|
+
* Исполнитель запроса
|
|
5
8
|
*/
|
|
6
9
|
export type QueryExecutor<TResult> = () => Promise<TResult>;
|
|
7
|
-
export type QueryParams<TResult, TError> = {
|
|
10
|
+
export type QueryParams<TResult, TError, TIsBackground extends boolean = false> = {
|
|
8
11
|
/**
|
|
9
|
-
*
|
|
12
|
+
* Обработчик ошибки, вызываемый по умолчанию
|
|
10
13
|
*/
|
|
11
14
|
onError?: SyncParams<TResult, TError>['onError'];
|
|
12
15
|
/**
|
|
13
|
-
*
|
|
16
|
+
* Флаг, отвечающий за автоматический запрос данных при обращении к полю data
|
|
14
17
|
*/
|
|
15
18
|
enabledAutoFetch?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Политика получения данных.
|
|
21
|
+
* @enum cache-first - данные сначала берутся из кеша, если их нет, тогда идет обращение к сети, ответ записывается в кэш
|
|
22
|
+
* @enum network-only - данные всегда берутся из сети, при этом ответ записывается в кэш
|
|
23
|
+
*/
|
|
16
24
|
fetchPolicy?: FetchPolicy;
|
|
17
25
|
/**
|
|
18
|
-
*
|
|
26
|
+
* Инстанс хранилища данных
|
|
19
27
|
*/
|
|
20
28
|
dataStorage: DataStorage<TResult>;
|
|
21
|
-
};
|
|
22
|
-
/**
|
|
23
|
-
* @description стор для работы с запросами,
|
|
24
|
-
* которые должны быть закешированы,
|
|
25
|
-
* но им не требуется усложнение в виде работы с фильтрами и инфинити запросами
|
|
26
|
-
*/
|
|
27
|
-
export declare class Query<TResult, TError = void> implements QueryBaseActions<TResult, TError, undefined> {
|
|
28
29
|
/**
|
|
29
|
-
*
|
|
30
|
+
* Инстанс хранилища основных статусов
|
|
30
31
|
*/
|
|
31
|
-
|
|
32
|
+
statusStorage: StatusStorage<TError>;
|
|
32
33
|
/**
|
|
33
|
-
*
|
|
34
|
+
* Инстанс хранилища фоновых статусов
|
|
34
35
|
*/
|
|
35
|
-
|
|
36
|
+
backgroundStatusStorage?: TIsBackground extends true ? StatusStorage<TError> : null | undefined;
|
|
36
37
|
/**
|
|
37
|
-
*
|
|
38
|
+
* Колбэк, вызываемый при успешном завершении запроса, подразумевается использование, для подтверждения валидности данных, чтобы квери не был удален из памяти
|
|
38
39
|
*/
|
|
39
|
-
|
|
40
|
+
submitValidity?: () => void;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Стор для работы с запросами,
|
|
44
|
+
* которые должны быть закешированы,
|
|
45
|
+
* но им не требуется усложнение в виде работы с фильтрами и инфинити запросами
|
|
46
|
+
*/
|
|
47
|
+
export declare class Query<TResult, TError = void, TIsBackground extends boolean = false> extends QueryContainer<TError, AuxiliaryQuery<TResult, TError>, TIsBackground> implements QueryBaseActions<TResult, TError, undefined> {
|
|
48
|
+
private readonly executor;
|
|
40
49
|
/**
|
|
41
|
-
*
|
|
42
|
-
* что будет использоваться что-то из слоя sources
|
|
50
|
+
* Хранилище данных, для обеспечения возможности синхронизации данных между разными инстансами
|
|
43
51
|
*/
|
|
44
|
-
private
|
|
52
|
+
private storage;
|
|
45
53
|
/**
|
|
46
|
-
*
|
|
54
|
+
* Обработчик ошибки, вызываемый по умолчанию
|
|
47
55
|
*/
|
|
48
56
|
private defaultOnError?;
|
|
49
57
|
/**
|
|
50
|
-
*
|
|
58
|
+
* Флаг, отвечающий за автоматический запрос данных при обращении к полю data
|
|
51
59
|
*/
|
|
52
60
|
private enabledAutoFetch?;
|
|
53
61
|
/**
|
|
54
|
-
*
|
|
62
|
+
* Стандартное поведение политики кеширования
|
|
55
63
|
*/
|
|
56
64
|
private readonly defaultFetchPolicy?;
|
|
57
|
-
|
|
65
|
+
/**
|
|
66
|
+
* Колбэк, вызываемый при успешном завершении запроса, подразумевается использование, для подтверждения валидности данных, чтобы квери не был удален из памяти
|
|
67
|
+
*/
|
|
68
|
+
private readonly submitValidity?;
|
|
69
|
+
constructor(executor: QueryExecutor<TResult>, { onError, enabledAutoFetch, fetchPolicy, dataStorage, statusStorage, backgroundStatusStorage, submitValidity, }: QueryParams<TResult, TError, TIsBackground>);
|
|
58
70
|
private get isNetworkOnly();
|
|
59
71
|
/**
|
|
60
|
-
*
|
|
72
|
+
* Метод для инвалидации данных
|
|
61
73
|
*/
|
|
62
74
|
invalidate: () => void;
|
|
63
75
|
/**
|
|
64
|
-
*
|
|
76
|
+
* Синхронный метод получения данных
|
|
65
77
|
*/
|
|
66
78
|
sync: Sync<TResult, TError, undefined>;
|
|
67
79
|
/**
|
|
68
|
-
*
|
|
80
|
+
* Обработчик успешного ответа
|
|
69
81
|
*/
|
|
70
82
|
private submitSuccess;
|
|
71
83
|
/**
|
|
72
|
-
*
|
|
84
|
+
* Форс метод для установки данных
|
|
73
85
|
*/
|
|
74
86
|
forceUpdate: (data: TResult) => void;
|
|
75
87
|
/**
|
|
76
|
-
*
|
|
88
|
+
* Метод для переиспользования синхронной логики запроса
|
|
77
89
|
*/
|
|
78
|
-
|
|
90
|
+
protected proceedSync: Sync<TResult, TError>;
|
|
79
91
|
/**
|
|
80
|
-
*
|
|
92
|
+
* Асинхронный метод получения данных,
|
|
81
93
|
* предполагается, что нужно будет самостоятельно обрабатывать ошибку
|
|
82
94
|
*/
|
|
83
95
|
async: () => Promise<TResult>;
|
|
84
96
|
/**
|
|
85
|
-
*
|
|
97
|
+
* Содержит реактивные данные
|
|
86
98
|
* благодаря mobx, при изменении isInvalid, свойство будет вычисляться заново,
|
|
87
99
|
* следовательно, стриггерится условие невалидности,
|
|
88
100
|
* и начнется запрос, в результате которого, данные обновятся
|
|
89
101
|
*/
|
|
90
102
|
get data(): TResult | undefined;
|
|
91
|
-
/**
|
|
92
|
-
* @description флаг загрузки данных
|
|
93
|
-
*/
|
|
94
|
-
get isLoading(): boolean;
|
|
95
|
-
/**
|
|
96
|
-
* @description флаг обозначающий, что последний запрос был зафейлен
|
|
97
|
-
*/
|
|
98
|
-
get isError(): boolean;
|
|
99
|
-
/**
|
|
100
|
-
* @description данные о последней ошибке
|
|
101
|
-
*/
|
|
102
|
-
get error(): TError | undefined;
|
|
103
|
-
/**
|
|
104
|
-
* @description флаг обозначающий, что последний запрос был успешно завершен
|
|
105
|
-
*/
|
|
106
|
-
get isSuccess(): boolean;
|
|
107
|
-
get isIdle(): boolean;
|
|
108
103
|
}
|
package/Query/Query.js
CHANGED
|
@@ -1,52 +1,48 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { action, computed, makeObservable, when } from 'mobx';
|
|
2
2
|
import { AuxiliaryQuery } from '../AuxiliaryQuery';
|
|
3
|
+
import { QueryContainer } from '../QueryContainer';
|
|
3
4
|
/**
|
|
4
|
-
*
|
|
5
|
+
* Стор для работы с запросами,
|
|
5
6
|
* которые должны быть закешированы,
|
|
6
7
|
* но им не требуется усложнение в виде работы с фильтрами и инфинити запросами
|
|
7
8
|
*/
|
|
8
|
-
export class Query {
|
|
9
|
-
constructor(executor, { onError, enabledAutoFetch, fetchPolicy, dataStorage, }) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
*/
|
|
13
|
-
this.auxiliary = new AuxiliaryQuery();
|
|
14
|
-
/**
|
|
15
|
-
* @description флаг, по которому реактивно определяется необходимость запуска инвалидации
|
|
16
|
-
*/
|
|
17
|
-
this.isInvalid = false;
|
|
9
|
+
export class Query extends QueryContainer {
|
|
10
|
+
constructor(executor, { onError, enabledAutoFetch, fetchPolicy, dataStorage, statusStorage, backgroundStatusStorage = null, submitValidity, }) {
|
|
11
|
+
super(statusStorage, backgroundStatusStorage, new AuxiliaryQuery(statusStorage, backgroundStatusStorage));
|
|
12
|
+
this.executor = executor;
|
|
18
13
|
/**
|
|
19
|
-
*
|
|
14
|
+
* Метод для инвалидации данных
|
|
20
15
|
*/
|
|
21
16
|
this.invalidate = () => {
|
|
22
|
-
this.
|
|
17
|
+
this.auxiliary.invalidate();
|
|
23
18
|
};
|
|
24
19
|
/**
|
|
25
|
-
*
|
|
20
|
+
* Синхронный метод получения данных
|
|
26
21
|
*/
|
|
27
22
|
this.sync = (params) => {
|
|
28
23
|
const isInstanceAllow = !(this.isLoading || this.isSuccess);
|
|
29
|
-
if (this.isNetworkOnly || this.isInvalid || isInstanceAllow) {
|
|
24
|
+
if (this.isNetworkOnly || this.auxiliary.isInvalid || isInstanceAllow) {
|
|
30
25
|
this.proceedSync(params);
|
|
31
26
|
}
|
|
32
27
|
};
|
|
33
28
|
/**
|
|
34
|
-
*
|
|
29
|
+
* Обработчик успешного ответа
|
|
35
30
|
*/
|
|
36
31
|
this.submitSuccess = (resData) => {
|
|
32
|
+
var _a;
|
|
37
33
|
this.storage.setData(resData);
|
|
38
|
-
this.
|
|
34
|
+
(_a = this.submitValidity) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
39
35
|
return resData;
|
|
40
36
|
};
|
|
41
37
|
/**
|
|
42
|
-
*
|
|
38
|
+
* Форс метод для установки данных
|
|
43
39
|
*/
|
|
44
40
|
this.forceUpdate = (data) => {
|
|
45
41
|
this.auxiliary.submitSuccess();
|
|
46
42
|
this.submitSuccess(data);
|
|
47
43
|
};
|
|
48
44
|
/**
|
|
49
|
-
*
|
|
45
|
+
* Метод для переиспользования синхронной логики запроса
|
|
50
46
|
*/
|
|
51
47
|
this.proceedSync = (options) => {
|
|
52
48
|
const { onSuccess, onError } = options || {};
|
|
@@ -67,29 +63,35 @@ export class Query {
|
|
|
67
63
|
});
|
|
68
64
|
};
|
|
69
65
|
/**
|
|
70
|
-
*
|
|
66
|
+
* Асинхронный метод получения данных,
|
|
71
67
|
* предполагается, что нужно будет самостоятельно обрабатывать ошибку
|
|
72
68
|
*/
|
|
73
69
|
this.async = () => {
|
|
74
|
-
if (!this.isNetworkOnly && this.isSuccess && !this.isInvalid) {
|
|
70
|
+
if (!this.isNetworkOnly && this.isSuccess && !this.auxiliary.isInvalid) {
|
|
75
71
|
return Promise.resolve(this.storage.data);
|
|
76
72
|
}
|
|
77
73
|
return this.auxiliary
|
|
78
74
|
.getUnifiedPromise(this.executor)
|
|
79
75
|
.then(this.submitSuccess);
|
|
80
76
|
};
|
|
81
|
-
this.executor = executor;
|
|
82
77
|
this.defaultOnError = onError;
|
|
83
78
|
this.enabledAutoFetch = enabledAutoFetch;
|
|
84
79
|
this.defaultFetchPolicy = fetchPolicy;
|
|
85
80
|
this.storage = dataStorage;
|
|
86
|
-
|
|
81
|
+
this.submitValidity = submitValidity;
|
|
82
|
+
makeObservable(this, {
|
|
83
|
+
async: action,
|
|
84
|
+
sync: action,
|
|
85
|
+
forceUpdate: action,
|
|
86
|
+
data: computed,
|
|
87
|
+
submitSuccess: action,
|
|
88
|
+
});
|
|
87
89
|
}
|
|
88
90
|
get isNetworkOnly() {
|
|
89
91
|
return this.defaultFetchPolicy === 'network-only';
|
|
90
92
|
}
|
|
91
93
|
/**
|
|
92
|
-
*
|
|
94
|
+
* Содержит реактивные данные
|
|
93
95
|
* благодаря mobx, при изменении isInvalid, свойство будет вычисляться заново,
|
|
94
96
|
* следовательно, стриггерится условие невалидности,
|
|
95
97
|
* и начнется запрос, в результате которого, данные обновятся
|
|
@@ -99,7 +101,7 @@ export class Query {
|
|
|
99
101
|
!this.isSuccess &&
|
|
100
102
|
!this.isLoading &&
|
|
101
103
|
!this.isError;
|
|
102
|
-
if (this.isInvalid || shouldSync) {
|
|
104
|
+
if (this.auxiliary.isInvalid || shouldSync) {
|
|
103
105
|
// т.к. при вызове апдейта, изменяются флаги, на которые подписан data,
|
|
104
106
|
// нужно вызывать этот экшн асинхронно
|
|
105
107
|
when(() => true, this.proceedSync);
|
|
@@ -107,31 +109,4 @@ export class Query {
|
|
|
107
109
|
// возвращаем имеющиеся данные
|
|
108
110
|
return this.storage.data;
|
|
109
111
|
}
|
|
110
|
-
/**
|
|
111
|
-
* @description флаг загрузки данных
|
|
112
|
-
*/
|
|
113
|
-
get isLoading() {
|
|
114
|
-
return this.auxiliary.isLoading;
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* @description флаг обозначающий, что последний запрос был зафейлен
|
|
118
|
-
*/
|
|
119
|
-
get isError() {
|
|
120
|
-
return this.auxiliary.isError;
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* @description данные о последней ошибке
|
|
124
|
-
*/
|
|
125
|
-
get error() {
|
|
126
|
-
return this.auxiliary.error;
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* @description флаг обозначающий, что последний запрос был успешно завершен
|
|
130
|
-
*/
|
|
131
|
-
get isSuccess() {
|
|
132
|
-
return this.auxiliary.isSuccess;
|
|
133
|
-
}
|
|
134
|
-
get isIdle() {
|
|
135
|
-
return this.auxiliary.isIdle;
|
|
136
|
-
}
|
|
137
112
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { type StatusStorage } from '../StatusStorage';
|
|
2
|
+
export type QueryContainerAuxiliary = {
|
|
3
|
+
isIdle: boolean;
|
|
4
|
+
};
|
|
5
|
+
type Statuses<TError> = StatusStorage<TError>;
|
|
6
|
+
/**
|
|
7
|
+
* Контейнер для бойлерплейт части,
|
|
8
|
+
* позволяет не повторять в каждом наследуемом классе использование стандартных статусов
|
|
9
|
+
*/
|
|
10
|
+
export declare abstract class QueryContainer<TError, TAuxiliary extends QueryContainerAuxiliary, TIsBackground extends boolean> implements Statuses<TError> {
|
|
11
|
+
private readonly statusStorage;
|
|
12
|
+
private readonly backgroundStatusStorage;
|
|
13
|
+
protected readonly auxiliary: TAuxiliary;
|
|
14
|
+
protected constructor(statusStorage: StatusStorage<TError>, backgroundStatusStorage: StatusStorage<TError> | null, auxiliary: TAuxiliary);
|
|
15
|
+
/**
|
|
16
|
+
* Флаг загрузки данных
|
|
17
|
+
*/
|
|
18
|
+
get isLoading(): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Флаг обозначающий, что последний запрос был зафейлен
|
|
21
|
+
*/
|
|
22
|
+
get isError(): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Данные о последней ошибке
|
|
25
|
+
*/
|
|
26
|
+
get error(): TError | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Флаг обозначающий, что последний запрос был успешно завершен
|
|
29
|
+
*/
|
|
30
|
+
get isSuccess(): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Флаг, обозначающий простаивание, т.е. запроса еще не было
|
|
33
|
+
*/
|
|
34
|
+
get isIdle(): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Статусы, изменяющиеся после первого успешного запроса в режиме isBackground: true
|
|
37
|
+
* @example
|
|
38
|
+
* const query = mobxQuery.createQuery(
|
|
39
|
+
* ['some cache key'],
|
|
40
|
+
* () => Promise.resolve('foo'),
|
|
41
|
+
* { isBackground: true }
|
|
42
|
+
* );
|
|
43
|
+
*
|
|
44
|
+
* await query.async();
|
|
45
|
+
* console.log(query.isLoading); // переключался в true на момент запроса
|
|
46
|
+
* console.log(query.isSuccess); // true
|
|
47
|
+
*
|
|
48
|
+
* query.invalidate();
|
|
49
|
+
* await query.async();
|
|
50
|
+
* console.log(query.isLoading); // не изменялся
|
|
51
|
+
* console.log(query.isSuccess); // остался неизменным - true
|
|
52
|
+
*
|
|
53
|
+
* console.log(query.background.isLoading); // переключался в true на момент обновления
|
|
54
|
+
* console.log(query.background.isSuccess); // true
|
|
55
|
+
*
|
|
56
|
+
* @exception isBackground:false (а так же по умолчанию) background не доступен, и равен null
|
|
57
|
+
* @exception Mutation не доступен в мутации и равен null
|
|
58
|
+
*/
|
|
59
|
+
get background(): TIsBackground extends true ? Statuses<TError> : null;
|
|
60
|
+
}
|
|
61
|
+
export {};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { computed, makeObservable } from 'mobx';
|
|
2
|
+
/**
|
|
3
|
+
* Контейнер для бойлерплейт части,
|
|
4
|
+
* позволяет не повторять в каждом наследуемом классе использование стандартных статусов
|
|
5
|
+
*/
|
|
6
|
+
export class QueryContainer {
|
|
7
|
+
constructor(statusStorage, backgroundStatusStorage, auxiliary) {
|
|
8
|
+
this.statusStorage = statusStorage;
|
|
9
|
+
this.backgroundStatusStorage = backgroundStatusStorage;
|
|
10
|
+
this.auxiliary = auxiliary;
|
|
11
|
+
makeObservable(this, {
|
|
12
|
+
error: computed,
|
|
13
|
+
isError: computed,
|
|
14
|
+
isIdle: computed,
|
|
15
|
+
isLoading: computed,
|
|
16
|
+
isSuccess: computed,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Флаг загрузки данных
|
|
21
|
+
*/
|
|
22
|
+
get isLoading() {
|
|
23
|
+
return this.statusStorage.isLoading;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Флаг обозначающий, что последний запрос был зафейлен
|
|
27
|
+
*/
|
|
28
|
+
get isError() {
|
|
29
|
+
return this.statusStorage.isError;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Данные о последней ошибке
|
|
33
|
+
*/
|
|
34
|
+
get error() {
|
|
35
|
+
return this.statusStorage.error;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Флаг обозначающий, что последний запрос был успешно завершен
|
|
39
|
+
*/
|
|
40
|
+
get isSuccess() {
|
|
41
|
+
return this.statusStorage.isSuccess;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Флаг, обозначающий простаивание, т.е. запроса еще не было
|
|
45
|
+
*/
|
|
46
|
+
get isIdle() {
|
|
47
|
+
return this.auxiliary.isIdle;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Статусы, изменяющиеся после первого успешного запроса в режиме isBackground: true
|
|
51
|
+
* @example
|
|
52
|
+
* const query = mobxQuery.createQuery(
|
|
53
|
+
* ['some cache key'],
|
|
54
|
+
* () => Promise.resolve('foo'),
|
|
55
|
+
* { isBackground: true }
|
|
56
|
+
* );
|
|
57
|
+
*
|
|
58
|
+
* await query.async();
|
|
59
|
+
* console.log(query.isLoading); // переключался в true на момент запроса
|
|
60
|
+
* console.log(query.isSuccess); // true
|
|
61
|
+
*
|
|
62
|
+
* query.invalidate();
|
|
63
|
+
* await query.async();
|
|
64
|
+
* console.log(query.isLoading); // не изменялся
|
|
65
|
+
* console.log(query.isSuccess); // остался неизменным - true
|
|
66
|
+
*
|
|
67
|
+
* console.log(query.background.isLoading); // переключался в true на момент обновления
|
|
68
|
+
* console.log(query.background.isSuccess); // true
|
|
69
|
+
*
|
|
70
|
+
* @exception isBackground:false (а так же по умолчанию) background не доступен, и равен null
|
|
71
|
+
* @exception Mutation не доступен в мутации и равен null
|
|
72
|
+
*/
|
|
73
|
+
get background() {
|
|
74
|
+
if (!this.backgroundStatusStorage) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
return this.backgroundStatusStorage;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './QueryContainer';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './QueryContainer';
|
package/README.md
CHANGED
|
@@ -342,6 +342,31 @@ console.log(query.isError); // 'true'
|
|
|
342
342
|
console.log(query.error); // 'foo'
|
|
343
343
|
```
|
|
344
344
|
|
|
345
|
+
## Режим фонового обновления
|
|
346
|
+
`Query` и `InfiniteQuery` имеют режим фонового обновления. Предполагается, что будет хорошо подходить для обновления данных через websocket.
|
|
347
|
+
|
|
348
|
+
В этом режиме, основные статусные флаги `isSuccess`, `isLoading`, `isError`, `error` будут изменяться до первого успешного запроса. Последующие запросы уже будут изменять статусные флаги под полем `background`
|
|
349
|
+
|
|
350
|
+
```ts
|
|
351
|
+
const query = mobxQuery.createQuery(
|
|
352
|
+
['some cache key'],
|
|
353
|
+
() => Promise.resolve('foo'),
|
|
354
|
+
{ isBackground: true }
|
|
355
|
+
);
|
|
356
|
+
|
|
357
|
+
await query.async();
|
|
358
|
+
console.log(query.isLoading); // переключался в true на момент запроса
|
|
359
|
+
console.log(query.isSuccess); // true
|
|
360
|
+
|
|
361
|
+
query.invalidate();
|
|
362
|
+
await query.async();
|
|
363
|
+
console.log(query.isLoading); // не изменялся
|
|
364
|
+
console.log(query.isSuccess); // остался неизменным - true
|
|
365
|
+
|
|
366
|
+
console.log(query.background.isLoading); // переключался в true на момент обновления
|
|
367
|
+
console.log(query.background.isSuccess); // true
|
|
368
|
+
```
|
|
369
|
+
|
|
345
370
|
# Тестирование
|
|
346
371
|
|
|
347
372
|
## Тестирование при включенном ```enabledAutoFetch```
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { StorageFactory } from '../StorageFactory';
|
|
2
|
+
export declare class StatusStorage<TError> {
|
|
3
|
+
constructor();
|
|
4
|
+
/**
|
|
5
|
+
* Флаг обозначающий загрузку данных
|
|
6
|
+
*/
|
|
7
|
+
isLoading: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Флаг обозначающий, что последний запрос был зафейлен
|
|
10
|
+
*/
|
|
11
|
+
isError: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Данные о последней ошибке
|
|
14
|
+
*/
|
|
15
|
+
error?: TError;
|
|
16
|
+
/**
|
|
17
|
+
* Флаг, обозначающий успешность завершения последнего запроса
|
|
18
|
+
*/
|
|
19
|
+
isSuccess: boolean;
|
|
20
|
+
}
|
|
21
|
+
export declare class StatusStorageFactory extends StorageFactory<StatusStorage<void>> {
|
|
22
|
+
constructor();
|
|
23
|
+
getStorage: <TError>(keyHash: string) => StatusStorage<TError>;
|
|
24
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { makeObservable, observable } from 'mobx';
|
|
2
|
+
import { StorageFactory } from '../StorageFactory';
|
|
3
|
+
export class StatusStorage {
|
|
4
|
+
constructor() {
|
|
5
|
+
/**
|
|
6
|
+
* Флаг обозначающий загрузку данных
|
|
7
|
+
*/
|
|
8
|
+
this.isLoading = false;
|
|
9
|
+
/**
|
|
10
|
+
* Флаг обозначающий, что последний запрос был зафейлен
|
|
11
|
+
*/
|
|
12
|
+
this.isError = false;
|
|
13
|
+
/**
|
|
14
|
+
* Данные о последней ошибке
|
|
15
|
+
*/
|
|
16
|
+
this.error = undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Флаг, обозначающий успешность завершения последнего запроса
|
|
19
|
+
*/
|
|
20
|
+
this.isSuccess = false;
|
|
21
|
+
makeObservable(this, {
|
|
22
|
+
error: observable,
|
|
23
|
+
isError: observable,
|
|
24
|
+
isLoading: observable,
|
|
25
|
+
isSuccess: observable,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export class StatusStorageFactory extends StorageFactory {
|
|
30
|
+
constructor() {
|
|
31
|
+
super(() => new StatusStorage());
|
|
32
|
+
this.getStorage = (keyHash) => {
|
|
33
|
+
return this.getInternalStorage(keyHash);
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './StatusStorage';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './StatusStorage';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare abstract class StorageFactory<TStorage extends {}> {
|
|
2
|
+
private readonly createStorage;
|
|
3
|
+
private readonly adaptableMap;
|
|
4
|
+
protected constructor(createStorage: () => TStorage);
|
|
5
|
+
/**
|
|
6
|
+
* Фабричный метод получения/создания инстанса хранилища по ключу
|
|
7
|
+
*/
|
|
8
|
+
getInternalStorage: (keyHash: string) => TStorage;
|
|
9
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { AdaptableMap } from '../AdaptableMap';
|
|
2
|
+
export class StorageFactory {
|
|
3
|
+
constructor(createStorage) {
|
|
4
|
+
this.createStorage = createStorage;
|
|
5
|
+
this.adaptableMap = new AdaptableMap();
|
|
6
|
+
/**
|
|
7
|
+
* Фабричный метод получения/создания инстанса хранилища по ключу
|
|
8
|
+
*/
|
|
9
|
+
this.getInternalStorage = (keyHash) => {
|
|
10
|
+
const storage = this.adaptableMap.get(keyHash);
|
|
11
|
+
if (!storage) {
|
|
12
|
+
const createdStorage = this.createStorage();
|
|
13
|
+
this.adaptableMap.set(keyHash, createdStorage);
|
|
14
|
+
return createdStorage;
|
|
15
|
+
}
|
|
16
|
+
return storage;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './StorageFactory';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './StorageFactory';
|