@ainias42/tanstack-ids 0.0.1 → 0.0.2

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.
@@ -3,15 +3,15 @@ import { NotFoundError } from '@/NotFoundError';
3
3
  import { create, windowScheduler } from '@yornaath/batshit';
4
4
  import { createInfiniteQuery, createQuery } from 'react-query-kit';
5
5
  import { generateQuery } from '@/generateQuery';
6
- import { hashKey, useQueries } from '@tanstack/react-query';
6
+ import { hashKey, useQueries, useQueryClient } from '@tanstack/react-query';
7
7
  import { hoistReactQueryKitAttributes } from '@/hoistReactQueryKitAttributes';
8
8
  import { useIndexedData } from '@/hooks/useIndexedData';
9
9
  import { useMemo, useRef } from 'react';
10
10
  import { useQueriesSubscribeToReload } from '@/QueryContext/useQuerySubscribeToReload';
11
- import type { CreateInfiniteQueryOptions, CreateQueryOptions } from 'react-query-kit';
11
+ import type { Awaitable, Override, URecord } from '@ainias42/js-helper';
12
+ import type { CreateInfiniteQueryOptions, CreateQueryOptions, QueryHookOptions } from 'react-query-kit';
12
13
  import type { QueriesResults } from '@tanstack/react-query/build/legacy/useQueries';
13
14
  import type { QueryClient, QueryFunctionContext, UseQueryOptions, UseQueryResult } from '@tanstack/react-query';
14
- import type { URecord } from '@ainias42/js-helper';
15
15
 
16
16
  export type Unpacked<T> = T extends (infer U)[] ? U : T;
17
17
 
@@ -96,10 +96,15 @@ export function generateIdsQuery<
96
96
  return returnData.current;
97
97
  }
98
98
 
99
- function useOneHook(identifier: IdType) {
100
- const result = useQueryHook({variables: [identifier]});
99
+ function useOneHook(identifier: IdType, otherAdditionalQueryOptions: Omit<
100
+ QueryHookOptions<Type, unknown, Type, [IdType]>,
101
+ 'context' | 'fetcher' | 'queryKey' | 'variables'
102
+ > & { reloadWithContext?: boolean } = {}) {
103
+ const result = useQueryHook({...otherAdditionalQueryOptions, variables: [identifier]});
104
+
105
+ const shouldReload = otherAdditionalQueryOptions.reloadWithContext ?? true;
101
106
  useQueriesSubscribeToReload(
102
- [hashKey(useQueryHook.getKey([identifier as DeepPartial<IdType>]))],
107
+ shouldReload ? [hashKey(useQueryHook.getKey([identifier as DeepPartial<IdType>]))] : [],
103
108
  result.isFetching,
104
109
  result.error
105
110
  );
@@ -175,26 +180,26 @@ export function generateIdsQuery<
175
180
  return hoistReactQueryKitAttributes(queryHook, useFilter);
176
181
  }
177
182
 
178
- function generateInfiniteQuery<PageParams, FuncArguments extends any[]>(
179
- queryClient: QueryClient,
183
+ function generateInfiniteQuery<PageParams, Meta, FuncArguments extends any[] = []>(
180
184
  {
181
185
  queryFn,
182
186
  ...options
183
187
  }: Omit<
184
- CreateInfiniteQueryOptions<IdType[], FuncArguments, Error, PageParams>,
188
+ CreateInfiniteQueryOptions<{ data: IdType[], meta: Meta }, FuncArguments, Error, PageParams>,
185
189
  'getNextPageParam' | 'getPreviousPageParam' | 'queryKey' | 'fetcher'
186
190
  > & {
187
191
  queryFn: (
188
192
  pageParams: PageParams,
189
193
  args: FuncArguments,
190
194
  context: QueryFunctionContext<[string, FuncArguments], PageParams>
191
- ) => Promise<Type[]> | Type[];
195
+ ) => Awaitable<{ data: Type[], meta: Meta }>;
192
196
  getNextPageParam: (options: {
193
197
  getLastPage: () => Type[];
194
198
  getAllPages: () => Type[][];
195
199
  lastPageParam: PageParams;
196
200
  allPageParams: PageParams[];
197
201
  lastPageLength: number;
202
+ lastPageMeta: Meta;
198
203
  }) => PageParams | undefined;
199
204
  getPreviousPageParam?: (options: {
200
205
  getFirstPage: () => Type[];
@@ -202,16 +207,35 @@ export function generateIdsQuery<
202
207
  firstPageParam: PageParams;
203
208
  allPageParams: PageParams[];
204
209
  firstPageLength: number;
210
+ firstPageMeta: Meta;
205
211
  }) => PageParams | undefined;
206
212
  }
207
213
  ) {
214
+ let queryClient: QueryClient | undefined;
215
+
216
+ function getQueryClient() {
217
+ if (!queryClient) {
218
+ throw new Error("QueryClient not set");
219
+ }
220
+ return queryClient;
221
+ }
222
+
208
223
  function findEntity(id: IdType) {
209
- return queryClient.getQueryData(useQueryHook.getKey([id as DeepPartial<IdType>])) as Type | undefined;
224
+ return getQueryClient().getQueryData(useQueryHook.getKey([id as DeepPartial<IdType>])) as Type | undefined;
210
225
  }
211
226
 
212
227
  const {getPreviousPageParam} = options;
213
- const infiniteQueryHook = createInfiniteQuery<IdType[], FuncArguments, Error, PageParams>({
228
+ const infiniteQueryHook = createInfiniteQuery<{
229
+ data: IdType[],
230
+ meta: Meta
231
+ }, FuncArguments, Error, PageParams>({
214
232
  ...options,
233
+ use: [function myTestMiddleware(useQueryNext) {
234
+ return (options, currentQueryClient) => {
235
+ queryClient = useQueryClient(currentQueryClient);
236
+ return useQueryNext(options, queryClient);
237
+ };
238
+ }],
215
239
  queryKey: [`${key}-infinite-query`],
216
240
  fetcher: async (_, ctx) => {
217
241
  const context = ctx as typeof ctx & { pageParam: PageParams };
@@ -220,41 +244,90 @@ export function generateIdsQuery<
220
244
  context.queryKey[1] as FuncArguments,
221
245
  context as QueryFunctionContext<[string, FuncArguments], PageParams>
222
246
  );
223
- return result.map(item => {
224
- queryClient.setQueryData(useQueryHook.getKey([item.id as DeepPartial<IdType>]), item);
225
- return item.id;
226
- });
247
+ return {
248
+ meta: result.meta,
249
+ data: result.data.map(item => {
250
+ getQueryClient().setQueryData(useQueryHook.getKey([item.id as DeepPartial<IdType>]), item);
251
+ return item.id;
252
+ })
253
+ };
227
254
  },
228
- getNextPageParam: (lastPage: IdType[], allPages: IdType[][], lastPageParam, allPageParams) => {
255
+ getNextPageParam: (lastPage: { meta: Meta, data: IdType[] }, allPages: {
256
+ meta: Meta,
257
+ data: IdType[]
258
+ }[], lastPageParam, allPageParams) => {
229
259
  return options.getNextPageParam({
230
- getLastPage: () => ArrayHelper.noUndefined(lastPage.map(findEntity)),
231
- getAllPages: () => allPages.map(page => ArrayHelper.noUndefined(page.map(findEntity))),
260
+ lastPageMeta: lastPage.meta,
261
+ getLastPage: () => ArrayHelper.noUndefined(lastPage.data.map(findEntity)),
262
+ getAllPages: () => allPages.map(page => ArrayHelper.noUndefined(page.data.map(findEntity))),
232
263
  lastPageParam,
233
264
  allPageParams,
234
- lastPageLength: lastPage.length
265
+ lastPageLength: lastPage.data.length
235
266
  });
236
267
  },
237
268
  getPreviousPageParam: !getPreviousPageParam
238
269
  ? undefined
239
270
  : (firstPage, allPages, firstPageParam, allPageParams) => {
240
271
  return getPreviousPageParam({
241
- getFirstPage: () => ArrayHelper.noUndefined(firstPage.map(findEntity)),
242
- getAllPages: () => allPages.map(page => ArrayHelper.noUndefined(page.map(findEntity))),
272
+ firstPageMeta: firstPage.meta,
273
+ getFirstPage: () => ArrayHelper.noUndefined(firstPage.data.map(findEntity)),
274
+ getAllPages: () => allPages.map(page => ArrayHelper.noUndefined(page.data.map(findEntity))),
243
275
  firstPageParam,
244
276
  allPageParams,
245
- firstPageLength: firstPage.length
277
+ firstPageLength: firstPage.data.length
246
278
  });
247
279
  }
248
280
  });
249
281
 
250
- function useInfiniteQuery(...args: FuncArguments) {
251
- const result = infiniteQueryHook({variables: args});
282
+
283
+ type HookOptions = Override<Parameters<typeof infiniteQueryHook>[0] & {
284
+ select?: undefined,
285
+ }, {
286
+ initialData?: {
287
+ pages: { data: Type[], meta: Meta }[],
288
+ pageParams: PageParams[]
289
+ }
290
+ }>;
291
+
292
+ type InfiniteQueryArgs = FuncArguments extends ({
293
+ length: 0
294
+ } | symbol | undefined) ? ([HookOptions] | []) : ([HookOptions]);
295
+
296
+ function useInfiniteQuery(...args: InfiniteQueryArgs) {
297
+ const infiniteQueryClient = useQueryClient();
298
+
299
+ let infiniteOptions: Parameters<typeof infiniteQueryHook>[0] & {
300
+ select?: undefined,
301
+ };
302
+ if (args.length === 1 && "initialData" in args[0] && args[0].initialData) {
303
+ const {initialData} = args[0];
304
+ infiniteOptions = {
305
+ ...args[0],
306
+ initialData: {
307
+ pages: initialData.pages.map(page => ({
308
+ ...page,
309
+ data: page.data.map(item => {
310
+ infiniteQueryClient.setQueryData(useQueryHook.getKey([item.id as DeepPartial<IdType>]), item);
311
+ return item.id;
312
+ })
313
+ })),
314
+ pageParams: initialData.pageParams
315
+ }
316
+ } as Parameters<typeof infiniteQueryHook>[0] & {
317
+ select?: undefined,
318
+ };
319
+ } else {
320
+ infiniteOptions = args[0] as Parameters<typeof infiniteQueryHook>[0] & {
321
+ select?: undefined,
322
+ };
323
+ }
324
+ const result = infiniteQueryHook(infiniteOptions);
252
325
  useQueriesSubscribeToReload(
253
- [hashKey(infiniteQueryHook.getKey(args as Parameters<(typeof infiniteQueryHook)['getKey']>[0]))],
326
+ [hashKey(infiniteQueryHook.getKey(infiniteOptions.variables as Parameters<(typeof infiniteQueryHook)['getKey']>[0]))],
254
327
  result.isFetching,
255
328
  result.error
256
329
  );
257
- const ids = useMemo(() => result.data?.pages.flat() ?? [], [result.data?.pages]);
330
+ const ids = useMemo(() => result.data?.pages.flatMap(page => page.data) ?? [], [result.data?.pages]);
258
331
 
259
332
  // When staleTime is same as filterStaleTime, then the queries will run at the same time as the filter
260
333
  // Because of this, use staleTime: Inifinity to prevent the queries from running again. The result of the
@@ -266,7 +339,7 @@ export function generateIdsQuery<
266
339
 
267
340
  const pages = useMemo(() => {
268
341
  return result.data
269
- ? result.data.pages.map(page => ArrayHelper.noUndefined(page.map(id => indexedData[id])))
342
+ ? result.data.pages.map(page => ArrayHelper.noUndefined(page.data.map(id => indexedData[id])))
270
343
  : [];
271
344
  }, [indexedData, result.data]);
272
345
 
@@ -276,7 +349,7 @@ export function generateIdsQuery<
276
349
  };
277
350
  }
278
351
 
279
- // @ts-expect-error type is okay
352
+ // @ts-expect-error wrong type in tanstack-query
280
353
  return hoistReactQueryKitAttributes(infiniteQueryHook, useInfiniteQuery);
281
354
  }
282
355
 
@@ -0,0 +1,12 @@
1
+ export function formatInitialPage<Type>(data?: Type, pageParam: any = 1) {
2
+ if (data) {
3
+ return {
4
+ initialData: {
5
+ pages: [data],
6
+ pageParams: [pageParam]
7
+ },
8
+ initialDataUpdatedAt: Date.now(),
9
+ };
10
+ }
11
+ return {};
12
+ }
package/src/index.ts CHANGED
@@ -4,6 +4,7 @@ export * from './generateQuery';
4
4
  export * from './hoistReactQueryKitAttributes';
5
5
  export * from './noop';
6
6
  export * from './NotFoundError';
7
+ export * from './hooks/formatInitialPage';
7
8
  export * from './hooks/useArrayData';
8
9
  export * from './hooks/useIndexedData';
9
10
  export * from './QueryContext/QueriesContext';