UNPKG

6.33 kBJavaScriptView Raw
1import { createClient } from '@urql/core';
2import { atom } from 'jotai';
3import { pipe, subscribe } from 'wonka';
4
5const DEFAULT_URL = (() => {
6 try {
7 return process.env.JOTAI_URQL_DEFAULT_URL;
8 } catch {
9 return void 0;
10 }
11})() || "/graphql";
12const clientAtom = atom(createClient({ url: DEFAULT_URL }));
13
14const isOperationResultWithData$1 = (result) => "data" in result && !result.error;
15function atomWithQuery(createQueryArgs, getClient = (get) => get(clientAtom)) {
16 const queryResultAtom = atom((get) => {
17 const args = createQueryArgs(get);
18 if (args.pause) {
19 return null;
20 }
21 const client = getClient(get);
22 let resolve = null;
23 const makePending = () => new Promise((r) => {
24 resolve = r;
25 });
26 const resultAtom = atom(makePending());
27 let setResult = null;
28 const listener = (result) => {
29 if (!resolve && !setResult) {
30 throw new Error("setting result without mount");
31 }
32 if (resolve) {
33 resolve(result);
34 resolve = null;
35 }
36 if (setResult) {
37 setResult(result);
38 }
39 };
40 let subscription = null;
41 let timer;
42 const startQuery = (opts) => {
43 if (subscription) {
44 clearTimeout(timer);
45 subscription.unsubscribe();
46 }
47 subscription = pipe(
48 client.query(args.query, args.variables, {
49 ...args.requestPolicy && { requestPolicy: args.requestPolicy },
50 ...args.context,
51 ...opts
52 }),
53 subscribe(listener)
54 );
55 if (!setResult) {
56 timer = setTimeout(() => {
57 if (subscription) {
58 subscription.unsubscribe();
59 subscription = null;
60 }
61 }, 1e3);
62 }
63 };
64 startQuery();
65 resultAtom.onMount = (update) => {
66 setResult = update;
67 if (subscription) {
68 clearTimeout(timer);
69 } else {
70 startQuery();
71 }
72 return () => {
73 setResult = null;
74 if (subscription) {
75 subscription.unsubscribe();
76 subscription = null;
77 }
78 };
79 };
80 return { resultAtom, makePending, startQuery };
81 });
82 const queryAtom = atom(
83 (get) => {
84 const queryResult = get(queryResultAtom);
85 if (!queryResult) {
86 return null;
87 }
88 const { resultAtom } = queryResult;
89 const result = get(resultAtom);
90 if (!isOperationResultWithData$1(result)) {
91 throw result.error;
92 }
93 return result;
94 },
95 (get, set, action) => {
96 if (action.type === "reexecute") {
97 console.warn(
98 "DEPRECATED [atomWithQuery] use refetch instead of reexecute"
99 );
100 action.type = "refetch";
101 }
102 switch (action.type) {
103 case "refetch": {
104 const queryResult = get(queryResultAtom);
105 if (!queryResult) {
106 throw new Error("query is paused");
107 }
108 const { resultAtom, makePending, startQuery } = queryResult;
109 set(resultAtom, makePending());
110 startQuery(action.opts);
111 return;
112 }
113 }
114 }
115 );
116 return queryAtom;
117}
118
119function atomWithMutation(createQuery, getClient = (get) => get(clientAtom)) {
120 const operationResultAtom = atom(
121 new Promise(() => {
122 })
123 );
124 const queryResultAtom = atom(
125 (get) => get(operationResultAtom),
126 async (get, set, action) => {
127 set(
128 operationResultAtom,
129 new Promise(() => {
130 })
131 );
132 const client = getClient(get);
133 const query = createQuery(get);
134 return client.mutation(query, action.variables, action.context).toPromise().then((result) => {
135 var _a;
136 (_a = action.callback) == null ? void 0 : _a.call(action, result);
137 if (result.error) {
138 throw result.error;
139 }
140 set(operationResultAtom, result);
141 });
142 }
143 );
144 return queryResultAtom;
145}
146
147const isOperationResultWithData = (result) => "data" in result && !result.error;
148function atomWithSubscription(createSubscriptionArgs, getClient = (get) => get(clientAtom)) {
149 const queryResultAtom = atom((get) => {
150 const args = createSubscriptionArgs(get);
151 if (args.pause) {
152 return null;
153 }
154 const client = getClient(get);
155 let resolve = null;
156 const makePending = () => new Promise((r) => {
157 resolve = r;
158 });
159 const resultAtom = atom(makePending());
160 let setResult = null;
161 const listener = (result) => {
162 if (resolve) {
163 resolve(result);
164 resolve = null;
165 }
166 if (setResult) {
167 setResult(result);
168 }
169 };
170 let subscription = null;
171 let timer;
172 const startSub = () => {
173 if (subscription) {
174 clearTimeout(timer);
175 subscription.unsubscribe();
176 }
177 subscription = pipe(
178 client.subscription(args.query, args.variables, args.context),
179 subscribe(listener)
180 );
181 if (!setResult) {
182 timer = setTimeout(() => {
183 if (subscription) {
184 subscription.unsubscribe();
185 subscription = null;
186 }
187 }, 1e3);
188 }
189 };
190 startSub();
191 resultAtom.onMount = (update) => {
192 setResult = update;
193 if (subscription) {
194 clearTimeout(timer);
195 } else {
196 startSub();
197 }
198 return () => {
199 setResult = null;
200 if (subscription) {
201 subscription.unsubscribe();
202 subscription = null;
203 }
204 };
205 };
206 return { resultAtom, makePending, startSub };
207 });
208 const queryAtom = atom(
209 (get) => {
210 const queryResult = get(queryResultAtom);
211 if (!queryResult) {
212 return null;
213 }
214 const { resultAtom } = queryResult;
215 const result = get(resultAtom);
216 if (!isOperationResultWithData(result)) {
217 throw result.error;
218 }
219 return result;
220 },
221 (get, set, action) => {
222 switch (action.type) {
223 case "refetch": {
224 const queryResult = get(queryResultAtom);
225 if (!queryResult) {
226 throw new Error("query is paused");
227 }
228 const { resultAtom, makePending, startSub } = queryResult;
229 set(resultAtom, makePending());
230 startSub();
231 return;
232 }
233 }
234 }
235 );
236 return queryAtom;
237}
238
239export { atomWithMutation, atomWithQuery, atomWithSubscription, clientAtom };