@pixotope/query 0.7.0 → 0.9.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/src/useQuery.ts CHANGED
@@ -7,7 +7,7 @@ export interface QueryOptions<
7
7
  TSelectData = TData,
8
8
  Stateless extends true | undefined = undefined,
9
9
  > {
10
- queryFn: (params: TParams | undefined | void) => Promise<TData>;
10
+ queryFn: (params: TParams | undefined | void, queryInfo: {key: TQueryKey | undefined, lastFetchedAt: number | undefined}) => Promise<TData>;
11
11
  onSuccess?: (data: TData) => Promise<void> | void;
12
12
  onError?: (error: TQueryError<TError>) => Promise<void> | void;
13
13
  onSettled?: (
@@ -189,7 +189,7 @@ export const useQuery = <
189
189
 
190
190
  try {
191
191
  const promises: RacePromises<TData>[] = [
192
- queryFnRef.current(params),
192
+ queryFnRef.current(params, { key: queryKeyPassed, lastFetchedAt: lastFetchedAt.current ?? undefined }),
193
193
  ...(internalOptionsRef.current.timeout
194
194
  ? [
195
195
  new Promise<RaceErrorReason>((resolve) =>
@@ -0,0 +1,79 @@
1
+ import { renderHook } from "@testing-library/react";
2
+ import { vi, describe, expect, it } from "vitest";
3
+
4
+ import {
5
+ buildServiceSubscriptionHook,
6
+ useSubscription,
7
+ } from "./useSubscription";
8
+
9
+ describe("useSubscription", () => {
10
+ it("should call subscription handler", () => {
11
+ const subscriptionHandler = vi.fn();
12
+ renderHook(() =>
13
+ useSubscription(subscriptionHandler, {
14
+ topic: "test",
15
+ service: "test",
16
+ })
17
+ );
18
+ expect(subscriptionHandler).toBeCalledTimes(1);
19
+ });
20
+
21
+ it("should correctly pass options to subscription handler", () => {
22
+ const subscriptionHandler = vi.fn();
23
+ renderHook(() =>
24
+ useSubscription(subscriptionHandler, {
25
+ topic: "test",
26
+ service: "test",
27
+ meta: { foo: "bar" },
28
+ maxDownwardDepth: 100,
29
+ })
30
+ );
31
+ expect(subscriptionHandler).toBeCalledTimes(1);
32
+ expect(subscriptionHandler).toHaveBeenCalledWith({
33
+ service: "test",
34
+ name: "test",
35
+ callback: expect.any(Function),
36
+ maxDownwardDepth: 100,
37
+ meta: { foo: "bar" },
38
+ });
39
+ });
40
+ });
41
+
42
+ describe("buildServiceSubscriptionHook", () => {
43
+ it("should correctly pass options to subscription handler", () => {
44
+ const subscriptionHandler = vi.fn();
45
+ const useHook = buildServiceSubscriptionHook(
46
+ subscriptionHandler,
47
+ () => "test"
48
+ );
49
+ renderHook(() => useHook({ topic: "test", meta: { foo: "bar" } }));
50
+ expect(subscriptionHandler).toHaveBeenCalledTimes(1);
51
+ expect(subscriptionHandler).toHaveBeenCalledWith(
52
+ expect.objectContaining({
53
+ service: "test",
54
+ name: "test",
55
+ meta: { foo: "bar" },
56
+ })
57
+ );
58
+ });
59
+
60
+ it("should correctly handle overridden machine", () => {
61
+ const subscriptionHandler = vi.fn();
62
+ const useHook = buildServiceSubscriptionHook(
63
+ subscriptionHandler,
64
+ (machine) => machine || "test"
65
+ );
66
+ renderHook(() =>
67
+ useHook({
68
+ topic: "test",
69
+ machine: "myCustomMachineName",
70
+ })
71
+ );
72
+ expect(subscriptionHandler).toHaveBeenCalledWith(
73
+ expect.objectContaining({
74
+ service: "myCustomMachineName",
75
+ name: "test",
76
+ })
77
+ );
78
+ });
79
+ });
@@ -7,6 +7,7 @@ export type SubscriptionOptions<
7
7
  TData,
8
8
  TMessage = unknown,
9
9
  Stateless extends true | undefined = undefined,
10
+ TMetadata extends {} = {},
10
11
  > = Omit<
11
12
  SubscriptionCoreOptions<TData, TMessage, Stateless>,
12
13
  "subscriberFn"
@@ -14,27 +15,35 @@ export type SubscriptionOptions<
14
15
  service: string;
15
16
  topic: string;
16
17
  maxDownwardDepth?: number;
18
+ } & {
19
+ meta?: TMetadata;
17
20
  };
18
21
 
19
- export type TSubscriptionHandlerFunction<TMessage> = (opts: {
20
- service: string;
21
- name: string;
22
- callback: (message: TMessage) => void;
23
- maxDownwardDepth?: number;
24
- }) => () => void;
22
+ export type TSubscriptionHandlerFunction<
23
+ TMessage,
24
+ TMetadata extends {} = {},
25
+ > = (
26
+ opts: {
27
+ service: string;
28
+ name: string;
29
+ callback: (message: TMessage) => void;
30
+ maxDownwardDepth?: number;
31
+ } & { meta?: TMetadata }
32
+ ) => () => void;
25
33
 
26
34
  export function useSubscription<
27
35
  TData = unknown,
28
36
  TMessage = TData,
29
37
  Stateless extends true | undefined = undefined,
38
+ TMetadata extends {} = {},
30
39
  >(
31
- subscriptionHandler: TSubscriptionHandlerFunction<TMessage>,
32
- options: SubscriptionOptions<TData, TMessage, Stateless>
40
+ subscriptionHandler: TSubscriptionHandlerFunction<TMessage, TMetadata>,
41
+ options: SubscriptionOptions<TData, TMessage, Stateless, TMetadata>
33
42
  ) {
34
- const { topic, service, maxDownwardDepth = 1000 } = options;
43
+ const { topic, service, maxDownwardDepth = 1000, meta, ...rest } = options;
35
44
 
36
45
  return useSubscriptionCore<TData, TMessage, Stateless>({
37
- ...options,
46
+ ...rest,
38
47
  subscriberFn: (handler) => {
39
48
  const unsubscribe = subscriptionHandler({
40
49
  service,
@@ -43,6 +52,7 @@ export function useSubscription<
43
52
  handler(message);
44
53
  },
45
54
  maxDownwardDepth,
55
+ meta,
46
56
  });
47
57
 
48
58
  return unsubscribe;
@@ -50,8 +60,8 @@ export function useSubscription<
50
60
  });
51
61
  }
52
62
 
53
- export function buildServiceSubscriptionHook(
54
- subscriptionHandler: TSubscriptionHandlerFunction<unknown>,
63
+ export function buildServiceSubscriptionHook<TMetadata extends {} = {}>(
64
+ subscriptionHandler: TSubscriptionHandlerFunction<unknown, TMetadata>,
55
65
  targetMachine: (machine: string | undefined) => string
56
66
  ) {
57
67
  return function useSubscriptionBuilder<
@@ -60,7 +70,7 @@ export function buildServiceSubscriptionHook(
60
70
  Stateless extends true | undefined = undefined,
61
71
  >(
62
72
  options: Omit<
63
- SubscriptionOptions<TData, TMessage, Stateless>,
73
+ SubscriptionOptions<TData, TMessage, Stateless, TMetadata>,
64
74
  "service"
65
75
  > & {
66
76
  machine?: string;
@@ -8,7 +8,8 @@
8
8
  import { shallowEqual } from "@pixotope/utils/comparison";
9
9
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
10
10
 
11
- type SubscriptionState = "idle" | "subscribed" | "subscribing";
11
+ type SubscriptionState = "idle" | "subscribed" | "subscribing" | "error";
12
+
12
13
  export type MessageHandler<TMessage> = (message: TMessage) => void;
13
14
  export type Connection = {
14
15
  acknowledge: () => void;
@@ -36,8 +37,9 @@ export type SubscriptionCoreOptions<
36
37
  */
37
38
  enabled?: boolean;
38
39
  /**
39
- * @description Function that will be called to compare the message with the
40
- * previous message. If the function returns true, the message will be ignored.
40
+ * @description Function that will be called before the message is processed.
41
+ * Returning `true` will cause the message to not be set to state and call {@link onError} if provided.
42
+ * Status will be set to `error`.
41
43
  */
42
44
  compareOrThrow?: (data: TMessage) => boolean;
43
45
  /**
@@ -165,6 +167,7 @@ export function useSubscriptionCore<
165
167
  const handler = useCallback(
166
168
  async (message: TMessage) => {
167
169
  if (internalCallbacksRef.current.compareOrThrow?.(message)) {
170
+ updateStatus("error");
168
171
  internalCallbacksRef.current.onError?.(message);
169
172
 
170
173
  return;