@ethlete/query 5.15.0 → 5.16.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.
Files changed (184) hide show
  1. package/.eslintrc.json +40 -0
  2. package/CHANGELOG.md +14 -0
  3. package/jest.config.ts +23 -0
  4. package/ng-package.json +8 -0
  5. package/package.json +6 -23
  6. package/project.json +37 -0
  7. package/{index.d.ts → src/index.ts} +2 -0
  8. package/src/lib/auth/auth-provider.types.ts +160 -0
  9. package/src/lib/auth/auth-provider.utils.ts +39 -0
  10. package/src/lib/auth/basic-auth-provider.ts +17 -0
  11. package/src/lib/auth/bearer-auth-provider.ts +243 -0
  12. package/src/lib/auth/custom-header-auth-provider.ts +13 -0
  13. package/{lib/class-validator/class-validator.types.d.ts → src/lib/class-validator/class-validator.types.ts} +4 -3
  14. package/src/lib/class-validator/class-validator.utils.ts +5 -0
  15. package/src/lib/devtools/components/query-devtools/query-devtools.component.html +402 -0
  16. package/src/lib/devtools/components/query-devtools/query-devtools.component.scss +360 -0
  17. package/src/lib/devtools/components/query-devtools/query-devtools.component.ts +427 -0
  18. package/src/lib/devtools/pipes/query-short-name.pipe.ts +24 -0
  19. package/src/lib/devtools/utils/query-client.utils.ts +25 -0
  20. package/src/lib/directives/infinity-query-trigger.directive.ts +58 -0
  21. package/src/lib/directives/infinity-query.directive.ts +208 -0
  22. package/src/lib/directives/query.directive.ts +201 -0
  23. package/src/lib/entity/entity-store.ts +180 -0
  24. package/src/lib/entity/entity.types.ts +34 -0
  25. package/src/lib/entity/entity.utils.ts +51 -0
  26. package/src/lib/gql/gql.ts +22 -0
  27. package/src/lib/infinite-query/infinity-query.ts +245 -0
  28. package/src/lib/infinite-query/infinity-query.types.ts +149 -0
  29. package/src/lib/infinite-query/infinity-query.utils.ts +14 -0
  30. package/src/lib/logger/logger.ts +30 -0
  31. package/src/lib/query/query.ts +631 -0
  32. package/src/lib/query/query.types.ts +532 -0
  33. package/src/lib/query/query.utils.spec.ts +92 -0
  34. package/src/lib/query/query.utils.ts +450 -0
  35. package/src/lib/query-client/query-client.spec.ts +77 -0
  36. package/src/lib/query-client/query-client.ts +195 -0
  37. package/src/lib/query-client/query-client.types.ts +101 -0
  38. package/src/lib/query-client/query-client.utils.spec.ts +61 -0
  39. package/src/lib/query-client/query-client.utils.ts +28 -0
  40. package/src/lib/query-creator/query-creator.ts +103 -0
  41. package/src/lib/query-creator/query-creator.types.ts +74 -0
  42. package/src/lib/query-form/query-form.ts +526 -0
  43. package/src/lib/query-form/query-form.types.ts +169 -0
  44. package/src/lib/query-form/query-form.utils.ts +116 -0
  45. package/src/lib/query-store/query-store.ts +192 -0
  46. package/src/lib/request/request.ts +253 -0
  47. package/src/lib/request/request.types.ts +164 -0
  48. package/src/lib/request/request.util.spec.ts +177 -0
  49. package/src/lib/request/request.util.ts +399 -0
  50. package/src/lib/stories/angular-example-page.mdx +85 -0
  51. package/src/lib/stories/authentication-page.mdx +35 -0
  52. package/src/lib/stories/changelog-page.mdx +9 -0
  53. package/src/lib/stories/client-page.mdx +100 -0
  54. package/src/lib/stories/queries-page.mdx +117 -0
  55. package/src/lib/symfony/symfony.types.ts +21 -0
  56. package/src/lib/symfony/symfony.utils.ts +43 -0
  57. package/src/lib/utils/data.utils.ts +280 -0
  58. package/src/lib/utils/deep-freeze.util.ts +21 -0
  59. package/{lib/utils/def.util.d.ts → src/lib/utils/def.util.ts} +1 -1
  60. package/src/test-setup.ts +1 -0
  61. package/tsconfig.json +29 -0
  62. package/tsconfig.lib.json +12 -0
  63. package/tsconfig.lib.prod.json +10 -0
  64. package/tsconfig.spec.json +11 -0
  65. package/esm2022/ethlete-query.mjs +0 -5
  66. package/esm2022/index.mjs +0 -20
  67. package/esm2022/lib/auth/auth-provider.types.mjs +0 -2
  68. package/esm2022/lib/auth/auth-provider.utils.mjs +0 -25
  69. package/esm2022/lib/auth/basic-auth-provider.mjs +0 -15
  70. package/esm2022/lib/auth/bearer-auth-provider.mjs +0 -168
  71. package/esm2022/lib/auth/custom-header-auth-provider.mjs +0 -12
  72. package/esm2022/lib/auth/index.mjs +0 -6
  73. package/esm2022/lib/class-validator/class-validator.types.mjs +0 -2
  74. package/esm2022/lib/class-validator/class-validator.utils.mjs +0 -4
  75. package/esm2022/lib/class-validator/index.mjs +0 -3
  76. package/esm2022/lib/devtools/components/query-devtools/index.mjs +0 -2
  77. package/esm2022/lib/devtools/components/query-devtools/query-devtools.component.mjs +0 -297
  78. package/esm2022/lib/devtools/pipes/index.mjs +0 -2
  79. package/esm2022/lib/devtools/pipes/query-short-name.pipe.mjs +0 -24
  80. package/esm2022/lib/devtools/utils/index.mjs +0 -2
  81. package/esm2022/lib/devtools/utils/query-client.utils.mjs +0 -13
  82. package/esm2022/lib/directives/index.mjs +0 -4
  83. package/esm2022/lib/directives/infinity-query-trigger.directive.mjs +0 -56
  84. package/esm2022/lib/directives/infinity-query.directive.mjs +0 -147
  85. package/esm2022/lib/directives/query.directive.mjs +0 -123
  86. package/esm2022/lib/entity/entity-store.mjs +0 -127
  87. package/esm2022/lib/entity/entity.types.mjs +0 -2
  88. package/esm2022/lib/entity/entity.utils.mjs +0 -29
  89. package/esm2022/lib/entity/index.mjs +0 -4
  90. package/esm2022/lib/gql/gql.mjs +0 -23
  91. package/esm2022/lib/gql/index.mjs +0 -2
  92. package/esm2022/lib/infinite-query/index.mjs +0 -4
  93. package/esm2022/lib/infinite-query/infinity-query.mjs +0 -171
  94. package/esm2022/lib/infinite-query/infinity-query.types.mjs +0 -2
  95. package/esm2022/lib/infinite-query/infinity-query.utils.mjs +0 -3
  96. package/esm2022/lib/logger/index.mjs +0 -2
  97. package/esm2022/lib/logger/logger.mjs +0 -16
  98. package/esm2022/lib/query/index.mjs +0 -4
  99. package/esm2022/lib/query/query.mjs +0 -428
  100. package/esm2022/lib/query/query.types.mjs +0 -2
  101. package/esm2022/lib/query/query.utils.mjs +0 -253
  102. package/esm2022/lib/query-client/index.mjs +0 -4
  103. package/esm2022/lib/query-client/query-client.mjs +0 -80
  104. package/esm2022/lib/query-client/query-client.types.mjs +0 -2
  105. package/esm2022/lib/query-client/query-client.utils.mjs +0 -20
  106. package/esm2022/lib/query-creator/index.mjs +0 -3
  107. package/esm2022/lib/query-creator/query-creator.mjs +0 -55
  108. package/esm2022/lib/query-creator/query-creator.types.mjs +0 -2
  109. package/esm2022/lib/query-form/index.mjs +0 -4
  110. package/esm2022/lib/query-form/query-form.mjs +0 -368
  111. package/esm2022/lib/query-form/query-form.types.mjs +0 -2
  112. package/esm2022/lib/query-form/query-form.utils.mjs +0 -97
  113. package/esm2022/lib/query-store/index.mjs +0 -2
  114. package/esm2022/lib/query-store/query-store.mjs +0 -144
  115. package/esm2022/lib/request/index.mjs +0 -4
  116. package/esm2022/lib/request/request.mjs +0 -196
  117. package/esm2022/lib/request/request.types.mjs +0 -2
  118. package/esm2022/lib/request/request.util.mjs +0 -252
  119. package/esm2022/lib/symfony/index.mjs +0 -3
  120. package/esm2022/lib/symfony/symfony.types.mjs +0 -2
  121. package/esm2022/lib/symfony/symfony.utils.mjs +0 -31
  122. package/esm2022/lib/utils/data.utils.mjs +0 -138
  123. package/esm2022/lib/utils/deep-freeze.util.mjs +0 -17
  124. package/esm2022/lib/utils/def.util.mjs +0 -8
  125. package/esm2022/lib/utils/index.mjs +0 -4
  126. package/fesm2022/ethlete-query.mjs +0 -3276
  127. package/fesm2022/ethlete-query.mjs.map +0 -1
  128. package/lib/auth/auth-provider.types.d.ts +0 -133
  129. package/lib/auth/auth-provider.utils.d.ts +0 -9
  130. package/lib/auth/basic-auth-provider.d.ts +0 -10
  131. package/lib/auth/bearer-auth-provider.d.ts +0 -23
  132. package/lib/auth/custom-header-auth-provider.d.ts +0 -9
  133. package/lib/class-validator/class-validator.utils.d.ts +0 -2
  134. package/lib/devtools/components/query-devtools/query-devtools.component.d.ts +0 -151
  135. package/lib/devtools/pipes/query-short-name.pipe.d.ts +0 -8
  136. package/lib/devtools/utils/query-client.utils.d.ts +0 -12
  137. package/lib/directives/infinity-query-trigger.directive.d.ts +0 -15
  138. package/lib/directives/infinity-query.directive.d.ts +0 -49
  139. package/lib/directives/query.directive.d.ts +0 -63
  140. package/lib/entity/entity-store.d.ts +0 -25
  141. package/lib/entity/entity.types.d.ts +0 -25
  142. package/lib/entity/entity.utils.d.ts +0 -12
  143. package/lib/gql/gql.d.ts +0 -6
  144. package/lib/infinite-query/infinity-query.d.ts +0 -29
  145. package/lib/infinite-query/infinity-query.types.d.ts +0 -104
  146. package/lib/infinite-query/infinity-query.utils.d.ts +0 -4
  147. package/lib/logger/logger.d.ts +0 -12
  148. package/lib/query/query.d.ts +0 -60
  149. package/lib/query/query.types.d.ts +0 -388
  150. package/lib/query/query.utils.d.ts +0 -91
  151. package/lib/query-client/query-client.d.ts +0 -29
  152. package/lib/query-client/query-client.types.d.ts +0 -82
  153. package/lib/query-client/query-client.utils.d.ts +0 -4
  154. package/lib/query-creator/query-creator.d.ts +0 -20
  155. package/lib/query-creator/query-creator.types.d.ts +0 -13
  156. package/lib/query-form/query-form.d.ts +0 -89
  157. package/lib/query-form/query-form.types.d.ts +0 -138
  158. package/lib/query-form/query-form.utils.d.ts +0 -13
  159. package/lib/query-store/query-store.d.ts +0 -31
  160. package/lib/request/request.d.ts +0 -3
  161. package/lib/request/request.types.d.ts +0 -126
  162. package/lib/request/request.util.d.ts +0 -92
  163. package/lib/symfony/symfony.types.d.ts +0 -19
  164. package/lib/symfony/symfony.utils.d.ts +0 -6
  165. package/lib/utils/data.utils.d.ts +0 -59
  166. package/lib/utils/deep-freeze.util.d.ts +0 -1
  167. /package/{lib/auth/index.d.ts → src/lib/auth/index.ts} +0 -0
  168. /package/{lib/class-validator/index.d.ts → src/lib/class-validator/index.ts} +0 -0
  169. /package/{lib/devtools/components/query-devtools/index.d.ts → src/lib/devtools/components/query-devtools/index.ts} +0 -0
  170. /package/{lib/devtools/pipes/index.d.ts → src/lib/devtools/pipes/index.ts} +0 -0
  171. /package/{lib/devtools/utils/index.d.ts → src/lib/devtools/utils/index.ts} +0 -0
  172. /package/{lib/directives/index.d.ts → src/lib/directives/index.ts} +0 -0
  173. /package/{lib/entity/index.d.ts → src/lib/entity/index.ts} +0 -0
  174. /package/{lib/gql/index.d.ts → src/lib/gql/index.ts} +0 -0
  175. /package/{lib/infinite-query/index.d.ts → src/lib/infinite-query/index.ts} +0 -0
  176. /package/{lib/logger/index.d.ts → src/lib/logger/index.ts} +0 -0
  177. /package/{lib/query/index.d.ts → src/lib/query/index.ts} +0 -0
  178. /package/{lib/query-client/index.d.ts → src/lib/query-client/index.ts} +0 -0
  179. /package/{lib/query-creator/index.d.ts → src/lib/query-creator/index.ts} +0 -0
  180. /package/{lib/query-form/index.d.ts → src/lib/query-form/index.ts} +0 -0
  181. /package/{lib/query-store/index.d.ts → src/lib/query-store/index.ts} +0 -0
  182. /package/{lib/request/index.d.ts → src/lib/request/index.ts} +0 -0
  183. /package/{lib/symfony/index.d.ts → src/lib/symfony/index.ts} +0 -0
  184. /package/{lib/utils/index.d.ts → src/lib/utils/index.ts} +0 -0
@@ -0,0 +1,532 @@
1
+ import { Observable } from 'rxjs';
2
+ import { EntityStore } from '../entity';
3
+ import { AnyQueryCreator, ConstructQuery, QueryDataOf, QueryResponseOf } from '../query-creator';
4
+ import { QueryForm } from '../query-form';
5
+ import { Method, PathParams, QueryParams, RequestError, RequestProgress } from '../request';
6
+ import { Query } from './query';
7
+
8
+ export interface QueryAutoRefreshConfig {
9
+ /**
10
+ * Refresh the query when the query client's headers change.
11
+ * @default true
12
+ */
13
+ queryClientDefaultHeadersChange?: boolean;
14
+
15
+ /**
16
+ * Refresh the query when the window regains focus.
17
+ *
18
+ * This can only be disabled if `autoRefreshQueriesOnWindowFocus` is enabled on the query client.
19
+ * @default true
20
+ */
21
+ windowFocus?: boolean;
22
+ }
23
+
24
+ export interface EntitySetParams<Store, Response, Arguments, Id> {
25
+ /**
26
+ * The response data.
27
+ */
28
+ response: Response;
29
+
30
+ /**
31
+ * The id(s) returned by the `id` function.
32
+ */
33
+ id: Id;
34
+
35
+ /**
36
+ * The arguments passed to the query.
37
+ */
38
+ args: Arguments;
39
+
40
+ /**
41
+ * The entity store.
42
+ */
43
+ store: Store;
44
+ }
45
+
46
+ export interface EntityGetParams<Store, Response, Arguments, Id> {
47
+ /**
48
+ * The response data.
49
+ */
50
+ response: Response;
51
+
52
+ /**
53
+ * The id(s) returned by the `id` function.
54
+ */
55
+ id: Id;
56
+
57
+ /**
58
+ * The arguments passed to the query.
59
+ */
60
+ args: Arguments;
61
+
62
+ /**
63
+ * The entity store.
64
+ */
65
+ store: Store;
66
+ }
67
+
68
+ export interface EntityIdParams<Response, Arguments> {
69
+ /**
70
+ * The response data.
71
+ */
72
+ response: Response;
73
+
74
+ /**
75
+ * The arguments passed to the query.
76
+ */
77
+ args: Arguments;
78
+ }
79
+
80
+ export interface QueryEntityConfig<Store, Data, Response, Arguments, Id> {
81
+ /**
82
+ * The entity store to use for the query.
83
+ */
84
+ store: Store;
85
+
86
+ /**
87
+ * A function that returns the id of the entity. Can also return an array of ids.
88
+ */
89
+ id: (data: EntityIdParams<Response, Arguments>) => Id;
90
+
91
+ /**
92
+ * A function that returns the response data (can be a subset of the response).
93
+ */
94
+ get?: (data: EntityGetParams<Store, Response, Arguments, Id>) => Observable<Data>;
95
+
96
+ /**
97
+ * A function to update the entity store every time a new response is received.
98
+ */
99
+ set?: (data: EntitySetParams<Store, Response, Arguments, Id>) => void;
100
+ }
101
+
102
+ export type QueryConfigBase<
103
+ Response,
104
+ Arguments extends BaseArguments | undefined,
105
+ Store extends EntityStore<unknown>,
106
+ Data,
107
+ Id,
108
+ > = {
109
+ /**
110
+ * The http method to use for the query.
111
+ */
112
+ method: Method;
113
+
114
+ /**
115
+ * Determines if the auth provider should be used for this query.
116
+ * The query **will throw** if the query client's auth provider is unset.
117
+ */
118
+ secure?: boolean;
119
+
120
+ /**
121
+ * Determines if the query should emit progress events.
122
+ */
123
+ reportProgress?: boolean;
124
+
125
+ /**
126
+ * Determines the query's response type.
127
+ * @default 'json'
128
+ */
129
+ responseType?: 'arraybuffer' | 'blob' | 'json' | 'text';
130
+
131
+ /**
132
+ * Whether this request should be sent with outgoing credentials (cookies).
133
+ * @default false
134
+ */
135
+ withCredentials?: boolean;
136
+
137
+ /**
138
+ * Configuration for handling auto refresh triggers.
139
+ *
140
+ * **Note:** This is only available for queries that can be refreshed. (`GET`, `HEAD`, `OPTIONS`, `GQL_QUERY`)
141
+ */
142
+ autoRefreshOn?: QueryAutoRefreshConfig;
143
+
144
+ /**
145
+ * Whether to automatically stop polling for this query when the window loses focus.
146
+ * Polling will resume when the window regains focus.
147
+ *
148
+ * This can only be disabled if `enableSmartPolling` is enabled on the query client.
149
+ * @default true
150
+ */
151
+ enableSmartPolling?: boolean;
152
+
153
+ /**
154
+ * Object containing the query's type information.
155
+ */
156
+ types?: {
157
+ /**
158
+ * The type of the successful response.
159
+ */
160
+ response?: Response;
161
+
162
+ /**
163
+ * Arguments for executing the query.
164
+ *
165
+ * - `pathParams`: The path parameters for the query. (in front of the ? in the url)
166
+ * - `queryParams`: The query parameters for the query. (after the ? in the url)
167
+ * - `body`: The body for the query. Unavailable for GET, HEAD and OPTIONS requests.
168
+ * - `headers`: The headers for the query.
169
+ * - `variables`: The variables for the query. (graphql only)
170
+ */
171
+ args?: Arguments;
172
+ };
173
+
174
+ /**
175
+ * Object containing the query's entity store information.
176
+ */
177
+ entity?: QueryEntityConfig<Store, Data, Response, Arguments, Id>;
178
+ };
179
+
180
+ export type RestQueryConfig<
181
+ Route extends RouteType<Arguments>,
182
+ Response,
183
+ Arguments extends BaseArguments | undefined,
184
+ Store extends EntityStore<unknown>,
185
+ Data,
186
+ Id,
187
+ > = QueryConfigBase<Response, Arguments, Store, Data, Id> & {
188
+ /**
189
+ * The api route to use for the query.
190
+ */
191
+ route: Route;
192
+ };
193
+
194
+ export type GqlTransferOption = 'GET' | 'POST';
195
+
196
+ export interface GqlQueryConfig<
197
+ Route extends RouteType<Arguments> | undefined,
198
+ Response,
199
+ Arguments extends BaseArguments | undefined,
200
+ Store extends EntityStore<unknown>,
201
+ Data,
202
+ Id,
203
+ > extends QueryConfigBase<Response, Arguments, Store, Data, Id> {
204
+ /**
205
+ * The graphql query to use for the query.
206
+ */
207
+ query: string;
208
+
209
+ /**
210
+ * Determines if the query should be sent via GET or POST.
211
+ * - `GET`: The query will be sent via query parameters.
212
+ * - `POST`: The query will be sent via the body.
213
+ * @default 'POST'
214
+ */
215
+ transferVia?: GqlTransferOption;
216
+
217
+ /**
218
+ * Subroute to use for the query.
219
+ */
220
+ route?: Route;
221
+ }
222
+
223
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
224
+ export type AnyRestQueryConfig = RestQueryConfig<any, any, any, any, any, any>;
225
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
226
+ export type AnyGqlQueryConfig = GqlQueryConfig<any, any, any, any, any, any>;
227
+
228
+ export type QueryConfigWithoutMethod<
229
+ Route extends RouteType<Arguments>,
230
+ Response,
231
+ Arguments extends BaseArguments | undefined,
232
+ Store extends EntityStore<unknown>,
233
+ Data,
234
+ Id,
235
+ > = Omit<RestQueryConfig<Route, Response, Arguments, Store, Data, Id>, 'method'>;
236
+
237
+ export type GqlQueryConfigWithoutMethod<
238
+ Route extends RouteType<Arguments>,
239
+ Response,
240
+ Arguments extends BaseArguments | undefined,
241
+ Store extends EntityStore<unknown>,
242
+ Data,
243
+ Id,
244
+ > = Omit<GqlQueryConfig<Route, Response, Arguments, Store, Data, Id>, 'method'>;
245
+
246
+ export type BaseArguments = WithHeaders &
247
+ WithVariables &
248
+ WithBody &
249
+ WithQueryParams &
250
+ WithPathParams &
251
+ WithMock<unknown>;
252
+
253
+ export interface WithHeaders {
254
+ /**
255
+ * The headers to send with the query.
256
+ */
257
+ headers?: Record<string, string>;
258
+ }
259
+
260
+ export interface QueryMockConfig<MockResponse> {
261
+ /**
262
+ * The mock response to use for the query.
263
+ */
264
+ response?: MockResponse;
265
+
266
+ /**
267
+ * The mock error to use for the query.
268
+ */
269
+ error?: RequestError;
270
+
271
+ /**
272
+ * The delay in milliseconds to wait before resolving the mock.
273
+ * If progress is enabled, the delay will be used for each progress event.
274
+ * @default 200
275
+ */
276
+ delay?: number;
277
+
278
+ /**
279
+ * Whether to report progress for the mock.
280
+ * For testing e.g. file uploads.
281
+ */
282
+ progress?: {
283
+ /**
284
+ * The number of progress events to report.
285
+ * @default 5
286
+ */
287
+ eventCount?: number;
288
+
289
+ /**
290
+ * The type of progress event to report.
291
+ * @default 'upload'
292
+ */
293
+ eventType?: 'download' | 'upload';
294
+
295
+ /**
296
+ * The total size of the file to report progress for in bytes.
297
+ * @default 1_000_000 (1MB)
298
+ */
299
+ fileSize?: number;
300
+
301
+ /**
302
+ * If true, the total size of the file will be omitted from the progress event.
303
+ * Useful for testing e.g. download progress when the server does not provide a total size.
304
+ */
305
+ omitTotal?: boolean;
306
+
307
+ /**
308
+ * If true, the partial text will be omitted from the progress event.
309
+ * Useful for testing e.g. download progress when the server does not provide a partial text.
310
+ */
311
+ omitPartialText?: boolean;
312
+ };
313
+
314
+ /**
315
+ * This will mock the request failing and getting retried 3 times. After, the request will succeed with the provided response.
316
+ * Can not be used with `progress` enabled.
317
+ * @default false
318
+ */
319
+ retryIntoResponse?: boolean;
320
+ }
321
+
322
+ export interface WithMock<MockResponse> {
323
+ mock?: QueryMockConfig<MockResponse>;
324
+ }
325
+
326
+ export interface QueryConfig {
327
+ /**
328
+ * Whether this query should be added to the internal query store.
329
+ *
330
+ * Generally this should be left on `false` unless you know what you are doing.
331
+ * @default false
332
+ */
333
+ skipQueryStore?: boolean;
334
+
335
+ /**
336
+ * The cache key to use for this query.
337
+ * Useful for queries that are equal but should be stored separately.
338
+ * Will be generated automatically if not provided.
339
+ *
340
+ * Generally this should be left on `undefined` unless you know what you are doing.
341
+ */
342
+ queryStoreCacheKey?: string;
343
+ }
344
+
345
+ export interface WithConfig {
346
+ /**
347
+ * Additional configuration for this query.
348
+ */
349
+ config?: QueryConfig;
350
+ }
351
+
352
+ export interface WithVariables {
353
+ /**
354
+ * The variables for the query. (graphql only)
355
+ */
356
+ variables?: Record<string, unknown>;
357
+ }
358
+
359
+ export interface WithBody {
360
+ /**
361
+ * The body for the query. Unavailable for GET, HEAD and OPTIONS requests.
362
+ */
363
+ body?: unknown;
364
+ }
365
+
366
+ export interface WithQueryParams {
367
+ /**
368
+ * The query parameters for the query. (after the ? in the url)
369
+ */
370
+ queryParams?: QueryParams;
371
+ }
372
+
373
+ export interface WithPathParams {
374
+ /**
375
+ * The path parameters for the query. (in front of the ? in the url)
376
+ */
377
+ pathParams?: PathParams;
378
+ }
379
+
380
+ export type QueryTrigger = 'program' | 'poll' | 'auto';
381
+
382
+ // eslint-disable-next-line @typescript-eslint/ban-types
383
+ export type EmptyObject = {};
384
+
385
+ export interface ExecuteQueryOptions {
386
+ /**
387
+ * Whether to skip the cache for this query. This will force the query to be executed. It might still be caught by the native browser cache.
388
+ * @default false
389
+ */
390
+ skipCache?: boolean;
391
+
392
+ /**
393
+ * Whether to cancel the previous request if it is still loading.
394
+ * @default false
395
+ */
396
+ cancelPrevious?: boolean;
397
+
398
+ /**
399
+ * The trigger type for this query.
400
+ * - `program`: The query was triggered by the user.
401
+ * - `poll`: The query was triggered by polling.
402
+ * - `auto`: The query was triggered by an auto refresh event.
403
+ * @default 'program'
404
+ * @internal
405
+ */
406
+ _triggeredVia?: QueryTrigger;
407
+
408
+ /**
409
+ * Whether this is a retry of an unauthorized request.
410
+ * @internal
411
+ */
412
+ _isUnauthorizedRetry?: boolean;
413
+ }
414
+
415
+ export type RouteType<Arguments extends BaseArguments | undefined> = Arguments extends {
416
+ pathParams: infer PathParams;
417
+ }
418
+ ? (p: PathParams) => RouteString
419
+ : RouteString;
420
+
421
+ export type RouteString = `/${string}`;
422
+
423
+ export type AnyRoute = ((p: PathParams) => string) | RouteString;
424
+
425
+ export interface PollConfig {
426
+ /**
427
+ * The interval in milliseconds to poll the query.
428
+ */
429
+ interval: number;
430
+
431
+ /**
432
+ * A observable that will stop the polling when it emits.
433
+ */
434
+ takeUntil: Observable<unknown>;
435
+
436
+ /**
437
+ * Whether to trigger the query immediately after polling starts.
438
+ */
439
+ triggerImmediately?: boolean;
440
+ }
441
+
442
+ export const enum QueryStateType {
443
+ Prepared = 'PREPARED',
444
+ Loading = 'LOADING',
445
+ Success = 'SUCCESS',
446
+ Failure = 'FAILURE',
447
+ Cancelled = 'CANCELLED',
448
+ }
449
+
450
+ export interface Prepared {
451
+ type: QueryStateType.Prepared;
452
+ meta: QueryStateMeta;
453
+ }
454
+
455
+ export interface Success<Response = unknown> {
456
+ type: QueryStateType.Success;
457
+ response: Response;
458
+ meta: QueryStateSuccessMeta;
459
+ }
460
+
461
+ export interface Failure {
462
+ type: QueryStateType.Failure;
463
+ error: RequestError;
464
+ meta: QueryStateMeta;
465
+ }
466
+
467
+ export interface Loading {
468
+ type: QueryStateType.Loading;
469
+ meta: QueryStateMeta;
470
+ partialText?: string;
471
+ progress?: RequestProgress;
472
+ }
473
+
474
+ export interface Cancelled {
475
+ type: QueryStateType.Cancelled;
476
+ meta: QueryStateMeta;
477
+ }
478
+
479
+ export interface QueryStateMeta {
480
+ id: number;
481
+ triggeredVia: QueryTrigger;
482
+ isWaitingForRetry?: boolean;
483
+ retryNumber?: number;
484
+ retryDelay?: number;
485
+ }
486
+
487
+ export interface QueryStateSuccessMeta extends QueryStateMeta {
488
+ expiresAt?: number;
489
+ }
490
+
491
+ export type QueryState<Response = unknown> = Loading | Success<Response> | Failure | Cancelled | Prepared;
492
+
493
+ export type QueryStateResponseOf<T extends QueryState = QueryState> =
494
+ T extends Success<infer Response> ? Response : never;
495
+
496
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
497
+ export type AnyQuery = Query<any, any, any, any, any, any>;
498
+
499
+ export type AnyQueryCreatorCollection = { [name: string]: AnyQueryCreator };
500
+
501
+ export type QueryCollectionOf<T extends { [name: string]: AnyQueryCreator }> = {
502
+ [K in keyof T]: { type: K; query: ConstructQuery<T[K]> };
503
+ }[keyof T];
504
+
505
+ export type AnyQueryCollection = QueryCollectionOf<AnyQueryCreatorCollection>;
506
+
507
+ export type QueryOf<T extends AnyQueryCollection | AnyQuery | null> = T extends AnyQuery
508
+ ? T
509
+ : T extends AnyQueryCollection
510
+ ? T['query']
511
+ : never;
512
+
513
+ export type AnyQueryCollectionResponse<T extends AnyQueryCollection> = QueryResponseOf<T['query']>;
514
+ export type AnyQueryCollectionData<T extends AnyQueryCollection> = QueryDataOf<T['query']>;
515
+
516
+ export type QueryCollectionKeysOf<T extends AnyQueryCollection | AnyQuery | null> = T extends AnyQueryCollection
517
+ ? T['type']
518
+ : never;
519
+
520
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
521
+ export interface ResetPageOnErrorOperatorConfig<J extends QueryForm<any>> {
522
+ /**
523
+ * The query form to reset the page of.
524
+ */
525
+ queryForm: J;
526
+
527
+ /**
528
+ * The key of the page control in the query form.
529
+ * @default 'page'
530
+ */
531
+ pageControlKey?: string;
532
+ }
@@ -0,0 +1,92 @@
1
+ import { Injector, runInInjectionContext } from '@angular/core';
2
+ import { TestBed } from '@angular/core/testing';
3
+ import { of } from 'rxjs';
4
+ import { QueryClient } from '../query-client';
5
+ import { QueryStateType } from './query.types';
6
+ import { createQueryCollectionSubject, switchQueryCollectionState, switchQueryState } from './query.utils';
7
+ const client = new QueryClient({
8
+ baseRoute: 'https://jsonplaceholder.typicode.com',
9
+ });
10
+
11
+ const postsQuery = client.get({
12
+ route: '/posts',
13
+ });
14
+
15
+ const posts2Query = client.get({
16
+ route: '/posts',
17
+ });
18
+
19
+ let injector: Injector;
20
+
21
+ beforeEach(() => {
22
+ TestBed.configureTestingModule({});
23
+
24
+ injector = TestBed.inject(Injector);
25
+ });
26
+
27
+ describe('switchQueryCollectionState', () => {
28
+ it('should switch to the query state observable and return the query state', (done) => {
29
+ runInInjectionContext(injector, () => {
30
+ const collection = createQueryCollectionSubject({ mediaWithDetailsQuery: postsQuery, mediaQuery: posts2Query });
31
+ collection.next({ type: 'mediaQuery', query: posts2Query.prepare() });
32
+
33
+ const result$ = switchQueryCollectionState()(collection);
34
+
35
+ result$.subscribe((result) => {
36
+ expect(result).toEqual({ meta: { id: 0, triggeredVia: 'program' }, type: QueryStateType.Prepared });
37
+
38
+ done();
39
+ });
40
+ });
41
+ });
42
+
43
+ it('should return null if the query state observable is null', (done) => {
44
+ runInInjectionContext(injector, () => {
45
+ const collection = createQueryCollectionSubject({ mediaWithDetailsQuery: postsQuery, mediaQuery: posts2Query });
46
+
47
+ const result$ = switchQueryCollectionState()(collection);
48
+
49
+ result$.subscribe((result) => {
50
+ expect(result).toBeNull();
51
+
52
+ done();
53
+ });
54
+ });
55
+ });
56
+ });
57
+
58
+ describe('switchQueryState', () => {
59
+ it('should switch to the query state observable and return the query state', (done) => {
60
+ const query = posts2Query.prepare();
61
+
62
+ const result$ = switchQueryState()(of(query));
63
+
64
+ result$.subscribe((result) => {
65
+ expect(result).toEqual({ meta: { id: 0, triggeredVia: 'program' }, type: QueryStateType.Prepared });
66
+
67
+ done();
68
+ });
69
+ });
70
+
71
+ it('should return null if the query state observable is null', (done) => {
72
+ const result$ = switchQueryState()(of(null));
73
+
74
+ result$.subscribe((result) => {
75
+ expect(result).toBeNull();
76
+
77
+ done();
78
+ });
79
+ });
80
+ });
81
+
82
+ // describe('takeUntilResponse', () => {
83
+ // it('should complete the observable when a successful response is received', (done) => {
84
+ // const query = postsQuery.prepare().execute();
85
+
86
+ // query.state$.pipe(takeUntilResponse()).subscribe({
87
+ // complete: () => {
88
+ // done();
89
+ // },
90
+ // });
91
+ // });
92
+ // });