1import { gql } from '@urql/core';
2import { it, expect, describe } from 'vitest';
3import { __initAnd_query as query } from '../operations/query';
4import { __initAnd_write as write } from '../operations/write';
5import { Store } from '../store/store';
6import { MergeMode, simplePagination } from './simplePagination';
7
8describe('as resolver', () => {
9 it('works with forward pagination', () => {
10 const Pagination = gql`
11 query ($skip: Number, $limit: Number) {
12 __typename
13 persons(skip: $skip, limit: $limit) {
14 __typename
15 id
16 name
17 }
18 }
19 `;
20
21 const store = new Store({
22 resolvers: {
23 Query: {
24 persons: simplePagination(),
25 },
26 },
27 });
28
29 const pageOne = {
30 __typename: 'Query',
31 persons: [
32 { id: 1, name: 'Jovi', __typename: 'Person' },
33 { id: 2, name: 'Phil', __typename: 'Person' },
34 { id: 3, name: 'Andy', __typename: 'Person' },
35 ],
36 };
37
38 const pageTwo = {
39 __typename: 'Query',
40 persons: [
41 { id: 4, name: 'Kadi', __typename: 'Person' },
42 { id: 5, name: 'Dom', __typename: 'Person' },
43 { id: 6, name: 'Sofia', __typename: 'Person' },
44 ],
45 };
46
47 write(
48 store,
49 { query: Pagination, variables: { skip: 0, limit: 3 } },
50 pageOne
51 );
52 const pageOneResult = query(store, {
53 query: Pagination,
54 variables: { skip: 0, limit: 3 },
55 });
56 expect(pageOneResult.data).toEqual(pageOne);
57
58 write(
59 store,
60 { query: Pagination, variables: { skip: 3, limit: 3 } },
61 pageTwo
62 );
63
64 const pageTwoResult = query(store, {
65 query: Pagination,
66 variables: { skip: 3, limit: 3 },
67 });
68 expect((pageTwoResult.data as any).persons).toEqual([
69 ...pageOne.persons,
70 ...pageTwo.persons,
71 ]);
72
73 const pageThreeResult = query(store, {
74 query: Pagination,
75 variables: { skip: 6, limit: 3 },
76 });
77 expect(pageThreeResult.data).toEqual(null);
78 });
79
80 it('works with backwards pagination', () => {
81 const Pagination = gql`
82 query ($skip: Number, $limit: Number) {
83 __typename
84 persons(skip: $skip, limit: $limit) {
85 __typename
86 id
87 name
88 }
89 }
90 `;
91
92 const store = new Store({
93 resolvers: {
94 Query: {
95 persons: simplePagination({ mergeMode: 'before' }),
96 },
97 },
98 });
99
100 const pageOne = {
101 __typename: 'Query',
102 persons: [
103 { id: 7, name: 'Jovi', __typename: 'Person' },
104 { id: 8, name: 'Phil', __typename: 'Person' },
105 { id: 9, name: 'Andy', __typename: 'Person' },
106 ],
107 };
108
109 const pageTwo = {
110 __typename: 'Query',
111 persons: [
112 { id: 4, name: 'Kadi', __typename: 'Person' },
113 { id: 5, name: 'Dom', __typename: 'Person' },
114 { id: 6, name: 'Sofia', __typename: 'Person' },
115 ],
116 };
117
118 write(
119 store,
120 { query: Pagination, variables: { skip: 0, limit: 3 } },
121 pageOne
122 );
123 const pageOneResult = query(store, {
124 query: Pagination,
125 variables: { skip: 0, limit: 3 },
126 });
127 expect(pageOneResult.data).toEqual(pageOne);
128
129 write(
130 store,
131 { query: Pagination, variables: { skip: 3, limit: 3 } },
132 pageTwo
133 );
134
135 const pageTwoResult = query(store, {
136 query: Pagination,
137 variables: { skip: 3, limit: 3 },
138 });
139 expect((pageTwoResult.data as any).persons).toEqual([
140 ...pageTwo.persons,
141 ...pageOne.persons,
142 ]);
143
144 const pageThreeResult = query(store, {
145 query: Pagination,
146 variables: { skip: 6, limit: 3 },
147 });
148 expect(pageThreeResult.data).toEqual(null);
149 });
150
151 it('handles duplicates', () => {
152 const Pagination = gql`
153 query ($skip: Number, $limit: Number) {
154 __typename
155 persons(skip: $skip, limit: $limit) {
156 __typename
157 id
158 name
159 }
160 }
161 `;
162
163 const store = new Store({
164 resolvers: {
165 Query: {
166 persons: simplePagination(),
167 },
168 },
169 });
170
171 const pageOne = {
172 __typename: 'Query',
173 persons: [
174 { id: 1, name: 'Jovi', __typename: 'Person' },
175 { id: 2, name: 'Phil', __typename: 'Person' },
176 { id: 3, name: 'Andy', __typename: 'Person' },
177 ],
178 };
179
180 const pageTwo = {
181 __typename: 'Query',
182 persons: [
183 { id: 3, name: 'Andy', __typename: 'Person' },
184 { id: 4, name: 'Kadi', __typename: 'Person' },
185 { id: 5, name: 'Dom', __typename: 'Person' },
186 ],
187 };
188
189 write(
190 store,
191 { query: Pagination, variables: { skip: 0, limit: 3 } },
192 pageOne
193 );
194 write(
195 store,
196 { query: Pagination, variables: { skip: 2, limit: 3 } },
197 pageTwo
198 );
199
200 const result = query(store, {
201 query: Pagination,
202 variables: { skip: 2, limit: 3 },
203 });
204 expect(result.data).toEqual({
205 __typename: 'Query',
206 persons: [...pageOne.persons, pageTwo.persons[1], pageTwo.persons[2]],
207 });
208 });
209
210 it('should not return previous result when adding a parameter', () => {
211 const Pagination = gql`
212 query ($skip: Number, $limit: Number, $filter: String) {
213 __typename
214 persons(skip: $skip, limit: $limit, filter: $filter) {
215 __typename
216 id
217 name
218 }
219 }
220 `;
221
222 const store = new Store({
223 resolvers: {
224 Query: {
225 persons: simplePagination(),
226 },
227 },
228 });
229
230 const pageOne = {
231 __typename: 'Query',
232 persons: [
233 { id: 1, name: 'Jovi', __typename: 'Person' },
234 { id: 2, name: 'Phil', __typename: 'Person' },
235 { id: 3, name: 'Andy', __typename: 'Person' },
236 ],
237 };
238
239 const emptyPage = {
240 __typename: 'Query',
241 persons: [],
242 };
243
244 write(
245 store,
246 { query: Pagination, variables: { skip: 0, limit: 3 } },
247 pageOne
248 );
249 write(
250 store,
251 { query: Pagination, variables: { skip: 0, limit: 3, filter: 'b' } },
252 emptyPage
253 );
254
255 const res = query(store, {
256 query: Pagination,
257 variables: { skip: 0, limit: 3, filter: 'b' },
258 });
259 expect(res.data).toEqual({ __typename: 'Query', persons: [] });
260 });
261
262 it('should preserve the correct order in forward pagination', () => {
263 const Pagination = gql`
264 query ($skip: Number, $limit: Number) {
265 __typename
266 persons(skip: $skip, limit: $limit) {
267 __typename
268 id
269 name
270 }
271 }
272 `;
273
274 const store = new Store({
275 resolvers: {
276 Query: {
277 persons: simplePagination({ mergeMode: 'after' }),
278 },
279 },
280 });
281
282 const pageOne = {
283 __typename: 'Query',
284 persons: [
285 { id: 1, name: 'Jovi', __typename: 'Person' },
286 { id: 2, name: 'Phil', __typename: 'Person' },
287 { id: 3, name: 'Andy', __typename: 'Person' },
288 ],
289 };
290
291 const pageTwo = {
292 __typename: 'Query',
293 persons: [
294 { id: 4, name: 'Kadi', __typename: 'Person' },
295 { id: 5, name: 'Dom', __typename: 'Person' },
296 { id: 6, name: 'Sofia', __typename: 'Person' },
297 ],
298 };
299
300 write(
301 store,
302 { query: Pagination, variables: { skip: 3, limit: 3 } },
303 pageTwo
304 );
305 write(
306 store,
307 { query: Pagination, variables: { skip: 0, limit: 3 } },
308 pageOne
309 );
310
311 const result = query(store, {
312 query: Pagination,
313 variables: { skip: 3, limit: 3 },
314 });
315 expect(result.data).toEqual({
316 __typename: 'Query',
317 persons: [...pageOne.persons, ...pageTwo.persons],
318 });
319 });
320
321 it('should preserve the correct order in backward pagination', () => {
322 const Pagination = gql`
323 query ($skip: Number, $limit: Number) {
324 __typename
325 persons(skip: $skip, limit: $limit) {
326 __typename
327 id
328 name
329 }
330 }
331 `;
332
333 const store = new Store({
334 resolvers: {
335 Query: {
336 persons: simplePagination({ mergeMode: 'before' }),
337 },
338 },
339 });
340
341 const pageOne = {
342 __typename: 'Query',
343 persons: [
344 { id: 7, name: 'Jovi', __typename: 'Person' },
345 { id: 8, name: 'Phil', __typename: 'Person' },
346 { id: 9, name: 'Andy', __typename: 'Person' },
347 ],
348 };
349
350 const pageTwo = {
351 __typename: 'Query',
352 persons: [
353 { id: 4, name: 'Kadi', __typename: 'Person' },
354 { id: 5, name: 'Dom', __typename: 'Person' },
355 { id: 6, name: 'Sofia', __typename: 'Person' },
356 ],
357 };
358
359 write(
360 store,
361 { query: Pagination, variables: { skip: 3, limit: 3 } },
362 pageTwo
363 );
364 write(
365 store,
366 { query: Pagination, variables: { skip: 0, limit: 3 } },
367 pageOne
368 );
369
370 const result = query(store, {
371 query: Pagination,
372 variables: { skip: 3, limit: 3 },
373 });
374
375 expect(result.data).toEqual({
376 __typename: 'Query',
377 persons: [...pageTwo.persons, ...pageOne.persons],
378 });
379 });
380
381 it('prevents overlapping of pagination on different arguments', () => {
382 const Pagination = gql`
383 query ($skip: Number, $limit: Number, $filter: string) {
384 __typename
385 persons(skip: $skip, limit: $limit, filter: $filter) {
386 __typename
387 id
388 name
389 }
390 }
391 `;
392
393 const store = new Store({
394 resolvers: {
395 Query: {
396 persons: simplePagination(),
397 },
398 },
399 });
400
401 const page = withId => ({
402 __typename: 'Query',
403 persons: [{ id: withId, name: withId, __typename: 'Person' }],
404 });
405
406 write(
407 store,
408 { query: Pagination, variables: { filter: 'one', skip: 0, limit: 1 } },
409 page('one')
410 );
411
412 write(
413 store,
414 { query: Pagination, variables: { filter: 'two', skip: 1, limit: 1 } },
415 page('two')
416 );
417
418 const resOne = query(store, {
419 query: Pagination,
420 variables: { filter: 'one', skip: 0, limit: 1 },
421 });
422 const resTwo = query(store, {
423 query: Pagination,
424 variables: { filter: 'two', skip: 1, limit: 1 },
425 });
426 const resThree = query(store, {
427 query: Pagination,
428 variables: { filter: 'three', skip: 2, limit: 1 },
429 });
430
431 expect(resOne.data).toHaveProperty('persons[0].id', 'one');
432 expect(resOne.data).toHaveProperty('persons.length', 1);
433
434 expect(resTwo.data).toHaveProperty('persons[0].id', 'two');
435 expect(resTwo.data).toHaveProperty('persons.length', 1);
436
437 expect(resThree.data).toEqual(null);
438 });
439});
440
441describe('as directive', () => {
442 it('works with forward pagination', () => {
443 const Pagination = gql`
444 query ($skip: Number, $limit: Number) {
445 __typename
446 persons(skip: $skip, limit: $limit) @_simplePagination {
447 __typename
448 id
449 name
450 }
451 }
452 `;
453
454 const store = new Store({
455 directives: {
456 simplePagination: () => simplePagination(),
457 },
458 });
459
460 const pageOne = {
461 __typename: 'Query',
462 persons: [
463 { id: 1, name: 'Jovi', __typename: 'Person' },
464 { id: 2, name: 'Phil', __typename: 'Person' },
465 { id: 3, name: 'Andy', __typename: 'Person' },
466 ],
467 };
468
469 const pageTwo = {
470 __typename: 'Query',
471 persons: [
472 { id: 4, name: 'Kadi', __typename: 'Person' },
473 { id: 5, name: 'Dom', __typename: 'Person' },
474 { id: 6, name: 'Sofia', __typename: 'Person' },
475 ],
476 };
477
478 write(
479 store,
480 { query: Pagination, variables: { skip: 0, limit: 3 } },
481 pageOne
482 );
483 const pageOneResult = query(store, {
484 query: Pagination,
485 variables: { skip: 0, limit: 3 },
486 });
487 expect(pageOneResult.data).toEqual(pageOne);
488
489 write(
490 store,
491 { query: Pagination, variables: { skip: 3, limit: 3 } },
492 pageTwo
493 );
494
495 const pageTwoResult = query(store, {
496 query: Pagination,
497 variables: { skip: 3, limit: 3 },
498 });
499
500 expect((pageTwoResult.data as any).persons).toEqual([
501 ...pageOne.persons,
502 ...pageTwo.persons,
503 ]);
504
505 const pageThreeResult = query(store, {
506 query: Pagination,
507 variables: { skip: 6, limit: 3 },
508 });
509 expect(pageThreeResult.data).toEqual(null);
510 });
511
512 it('works with backwards pagination', () => {
513 const Pagination = gql`
514 query ($skip: Number, $limit: Number) {
515 __typename
516 persons(skip: $skip, limit: $limit)
517 @_simplePagination(mergeMode: "before") {
518 __typename
519 id
520 name
521 }
522 }
523 `;
524
525 const store = new Store({
526 directives: {
527 simplePagination: directiveArguments =>
528 simplePagination({
529 mergeMode: directiveArguments!.mergeMode as MergeMode,
530 }),
531 },
532 });
533
534 const pageOne = {
535 __typename: 'Query',
536 persons: [
537 { id: 7, name: 'Jovi', __typename: 'Person' },
538 { id: 8, name: 'Phil', __typename: 'Person' },
539 { id: 9, name: 'Andy', __typename: 'Person' },
540 ],
541 };
542
543 const pageTwo = {
544 __typename: 'Query',
545 persons: [
546 { id: 4, name: 'Kadi', __typename: 'Person' },
547 { id: 5, name: 'Dom', __typename: 'Person' },
548 { id: 6, name: 'Sofia', __typename: 'Person' },
549 ],
550 };
551
552 write(
553 store,
554 { query: Pagination, variables: { skip: 0, limit: 3 } },
555 pageOne
556 );
557 const pageOneResult = query(store, {
558 query: Pagination,
559 variables: { skip: 0, limit: 3 },
560 });
561 expect(pageOneResult.data).toEqual(pageOne);
562
563 write(
564 store,
565 { query: Pagination, variables: { skip: 3, limit: 3 } },
566 pageTwo
567 );
568
569 const pageTwoResult = query(store, {
570 query: Pagination,
571 variables: { skip: 3, limit: 3 },
572 });
573 expect((pageTwoResult.data as any).persons).toEqual([
574 ...pageTwo.persons,
575 ...pageOne.persons,
576 ]);
577
578 const pageThreeResult = query(store, {
579 query: Pagination,
580 variables: { skip: 6, limit: 3 },
581 });
582 expect(pageThreeResult.data).toEqual(null);
583 });
584});