From 1cbc262af78973c4d4ad812df85ecf137f7f08e9 Mon Sep 17 00:00:00 2001 From: Ilia Mashkov Date: Wed, 15 Apr 2026 12:06:32 +0300 Subject: [PATCH] feat: add stable query key factory --- src/shared/api/queryKeys.test.ts | 48 ++++++++++++++++++++++++++++++++ src/shared/api/queryKeys.ts | 23 +++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 src/shared/api/queryKeys.test.ts create mode 100644 src/shared/api/queryKeys.ts diff --git a/src/shared/api/queryKeys.test.ts b/src/shared/api/queryKeys.test.ts new file mode 100644 index 0000000..a7f3911 --- /dev/null +++ b/src/shared/api/queryKeys.test.ts @@ -0,0 +1,48 @@ +import { + describe, + expect, + it, +} from 'vitest'; +import { fontKeys } from './queryKeys'; + +describe('fontKeys', () => { + describe('Hierarchy', () => { + it('should generate base keys', () => { + expect(fontKeys.all).toEqual(['fonts']); + expect(fontKeys.lists()).toEqual(['fonts', 'list']); + expect(fontKeys.batches()).toEqual(['fonts', 'batch']); + expect(fontKeys.details()).toEqual(['fonts', 'detail']); + }); + }); + + describe('Batch Keys (Stability & Sorting)', () => { + it('should sort IDs for stable serialization', () => { + const key1 = fontKeys.batch(['b', 'a', 'c']); + const key2 = fontKeys.batch(['c', 'b', 'a']); + const expected = ['fonts', 'batch', ['a', 'b', 'c']]; + expect(key1).toEqual(expected); + expect(key2).toEqual(expected); + }); + + it('should handle empty ID arrays', () => { + expect(fontKeys.batch([])).toEqual(['fonts', 'batch', []]); + }); + }); + + describe('List Keys (Parameters)', () => { + it('should include parameters in list keys', () => { + const params = { provider: 'google' }; + expect(fontKeys.list(params)).toEqual(['fonts', 'list', params]); + }); + + it('should handle empty parameters', () => { + expect(fontKeys.list({})).toEqual(['fonts', 'list', {}]); + }); + }); + + describe('Detail Keys', () => { + it('should generate unique detail keys per ID', () => { + expect(fontKeys.detail('roboto')).toEqual(['fonts', 'detail', 'roboto']); + }); + }); +}); diff --git a/src/shared/api/queryKeys.ts b/src/shared/api/queryKeys.ts new file mode 100644 index 0000000..93e5661 --- /dev/null +++ b/src/shared/api/queryKeys.ts @@ -0,0 +1,23 @@ +/** + * Stable query key factory for font-related queries. + * Ensures consistent serialization for batch requests by sorting IDs. + */ +export const fontKeys = { + /** Base key for all font queries */ + all: ['fonts'] as const, + + /** Keys for font list queries */ + lists: () => [...fontKeys.all, 'list'] as const, + /** Specific font list key with filter parameters */ + list: (params: object) => [...fontKeys.lists(), params] as const, + + /** Keys for font batch queries */ + batches: () => [...fontKeys.all, 'batch'] as const, + /** Specific batch key, sorted for stability */ + batch: (ids: string[]) => [...fontKeys.batches(), [...ids].sort()] as const, + + /** Keys for font detail queries */ + details: () => [...fontKeys.all, 'detail'] as const, + /** Specific font detail key by ID */ + detail: (id: string) => [...fontKeys.details(), id] as const, +} as const;