refactor queryRequest

This commit is contained in:
pa
2026-03-09 23:59:19 +09:00
parent 8f802ecf28
commit 21489fb717
17 changed files with 312 additions and 418 deletions
+109 -31
View File
@@ -3,25 +3,6 @@ import { describe, expect, test } from 'vitest';
import { queryKeys } from '../keys';
describe('query key shapes', () => {
test('favorite world keys include owner and tag dimensions', () => {
const a = queryKeys.favoriteWorlds({
n: 100,
offset: 0,
ownerId: 'usr_1',
userId: 'usr_1',
tag: 'worlds1'
});
const b = queryKeys.favoriteWorlds({
n: 100,
offset: 0,
ownerId: 'usr_2',
userId: 'usr_2',
tag: 'worlds1'
});
expect(a).not.toEqual(b);
});
test('world list keys include query option discriminator', () => {
const base = {
userId: 'usr_me',
@@ -42,22 +23,119 @@ describe('query key shapes', () => {
expect(defaultKey).not.toEqual(featuredKey);
});
test('group member list keys include sort and role dimensions', () => {
const everyone = queryKeys.groupMembers({
test('groupCalendarEvent key includes groupId and eventId', () => {
const a = queryKeys.groupCalendarEvent({
groupId: 'grp_1',
n: 100,
offset: 0,
sort: 'joinedAt:desc',
roleId: ''
eventId: 'evt_1'
});
const roleScoped = queryKeys.groupMembers({
const b = queryKeys.groupCalendarEvent({
groupId: 'grp_1',
n: 100,
offset: 0,
sort: 'joinedAt:desc',
roleId: 'grol_1'
eventId: 'evt_2'
});
expect(everyone).not.toEqual(roleScoped);
expect(a).not.toEqual(b);
expect(a).toEqual(['group', 'grp_1', 'calendarEvent', 'evt_1']);
});
test('userInventoryItem key scopes by both userId and inventoryId', () => {
const a = queryKeys.userInventoryItem({
inventoryId: 'inv_1',
userId: 'usr_1'
});
const b = queryKeys.userInventoryItem({
inventoryId: 'inv_1',
userId: 'usr_2'
});
expect(a).not.toEqual(b);
});
test('mutualCounts key is unique per userId', () => {
const a = queryKeys.mutualCounts('usr_1');
const b = queryKeys.mutualCounts('usr_2');
expect(a).not.toEqual(b);
expect(a).toEqual(['user', 'usr_1', 'mutualCounts']);
});
test('representedGroup key is unique per userId', () => {
const a = queryKeys.representedGroup('usr_1');
const b = queryKeys.representedGroup('usr_2');
expect(a).not.toEqual(b);
expect(a).toEqual(['user', 'usr_1', 'representedGroup']);
});
test('avatarStyles returns a stable singleton key', () => {
expect(queryKeys.avatarStyles()).toEqual(['avatar', 'styles']);
expect(queryKeys.avatarStyles()).toEqual(queryKeys.avatarStyles());
});
test('vrchatCredits returns a stable singleton key', () => {
expect(queryKeys.vrchatCredits()).toEqual(['credits']);
});
test('visits returns a stable singleton key', () => {
expect(queryKeys.visits()).toEqual(['visits']);
});
test('favoriteLimits returns a stable singleton key', () => {
expect(queryKeys.favoriteLimits()).toEqual(['favorite', 'limits']);
});
test('groupMember key includes both groupId and userId', () => {
const key = queryKeys.groupMember({
groupId: 'grp_1',
userId: 'usr_1'
});
expect(key).toEqual(['group', 'grp_1', 'member', 'usr_1']);
});
test('group key differentiates includeRoles flag', () => {
const withRoles = queryKeys.group('grp_1', true);
const withoutRoles = queryKeys.group('grp_1', false);
expect(withRoles).not.toEqual(withoutRoles);
});
test('worldPersistData key scopes by worldId', () => {
const a = queryKeys.worldPersistData('wrld_1');
const b = queryKeys.worldPersistData('wrld_2');
expect(a).not.toEqual(b);
expect(a).toEqual(['world', 'wrld_1', 'persistData']);
});
test('fileAnalysis key differentiates version and variant', () => {
const a = queryKeys.fileAnalysis({
fileId: 'file_1',
version: 1,
variant: 'default'
});
const b = queryKeys.fileAnalysis({
fileId: 'file_1',
version: 2,
variant: 'default'
});
const c = queryKeys.fileAnalysis({
fileId: 'file_1',
version: 1,
variant: 'hd'
});
expect(a).not.toEqual(b);
expect(a).not.toEqual(c);
});
test('worldsByUser key coerces numeric params consistently', () => {
const a = queryKeys.worldsByUser({
userId: 'usr_1',
n: '50',
offset: '0'
});
const b = queryKeys.worldsByUser({ userId: 'usr_1', n: 50, offset: 0 });
expect(a).toEqual(b);
});
});
+109 -66
View File
@@ -1,12 +1,9 @@
import { describe, expect, test } from 'vitest';
import {
entityQueryPolicies,
toQueryOptions
} from '../policies';
import { entityQueryPolicies, toQueryOptions } from '../policies';
describe('query policy configuration', () => {
test('matches the finalized cache strategy', () => {
test('core entity policies have correct stale/gc times', () => {
expect(entityQueryPolicies.user).toMatchObject({
staleTime: 20000,
gcTime: 90000,
@@ -34,64 +31,37 @@ describe('query policy configuration', () => {
retry: 1,
refetchOnWindowFocus: false
});
});
test('group sub-resource policies', () => {
expect(entityQueryPolicies.groupCollection).toMatchObject({
staleTime: 60000,
gcTime: 300000,
retry: 1,
refetchOnWindowFocus: false
});
expect(entityQueryPolicies.groupCalendarCollection).toMatchObject({
staleTime: 120000,
gcTime: 600000,
retry: 1,
refetchOnWindowFocus: false
});
expect(
entityQueryPolicies.groupFollowingCalendarCollection
).toMatchObject({
staleTime: 60000,
gcTime: 300000,
retry: 1,
refetchOnWindowFocus: false
});
expect(entityQueryPolicies.groupFeaturedCalendarCollection).toMatchObject({
staleTime: 300000,
gcTime: 900000,
retry: 1,
refetchOnWindowFocus: false
});
expect(entityQueryPolicies.groupCalendarEvent).toMatchObject({
staleTime: 120000,
gcTime: 600000,
retry: 1,
refetchOnWindowFocus: false
});
});
test('world collection policy', () => {
expect(entityQueryPolicies.worldCollection).toMatchObject({
staleTime: 60000,
gcTime: 300000,
retry: 1,
refetchOnWindowFocus: false
});
});
expect(entityQueryPolicies.friendList).toMatchObject({
staleTime: 20000,
gcTime: 90000,
retry: 1,
refetchOnWindowFocus: false
});
expect(entityQueryPolicies.favoriteCollection).toMatchObject({
staleTime: 60000,
gcTime: 300000,
retry: 1,
refetchOnWindowFocus: false
});
expect(entityQueryPolicies.galleryCollection).toMatchObject({
staleTime: 60000,
gcTime: 300000,
test('favorite and inventory policies', () => {
expect(entityQueryPolicies.favoriteLimits).toMatchObject({
staleTime: 600000,
gcTime: 1800000,
retry: 1,
refetchOnWindowFocus: false
});
@@ -102,42 +72,28 @@ describe('query policy configuration', () => {
retry: 1,
refetchOnWindowFocus: false
});
expect(entityQueryPolicies.inventoryObject).toMatchObject({
staleTime: 60000,
gcTime: 300000,
retry: 1,
refetchOnWindowFocus: false
});
});
test('avatar gallery policy has shorter staleTime than avatar entity', () => {
expect(entityQueryPolicies.avatarGallery).toMatchObject({
staleTime: 30000,
gcTime: 120000,
retry: 1,
refetchOnWindowFocus: false
});
expect(entityQueryPolicies.avatarGallery.staleTime).toBeLessThan(
entityQueryPolicies.avatar.staleTime
);
});
test('file-related policies', () => {
expect(entityQueryPolicies.fileAnalysis).toMatchObject({
staleTime: 120000,
gcTime: 600000,
retry: 1,
refetchOnWindowFocus: false
});
expect(entityQueryPolicies.worldPersistData).toMatchObject({
staleTime: 120000,
gcTime: 600000,
retry: 1,
refetchOnWindowFocus: false
});
expect(entityQueryPolicies.mutualCounts).toMatchObject({
staleTime: 120000,
gcTime: 600000,
retry: 1,
refetchOnWindowFocus: false
});
expect(entityQueryPolicies.visits).toMatchObject({
staleTime: 300000,
gcTime: 900000,
retry: 1,
refetchOnWindowFocus: false
});
expect(entityQueryPolicies.fileObject).toMatchObject({
staleTime: 60000,
@@ -147,6 +103,63 @@ describe('query policy configuration', () => {
});
});
test('world persist data policy', () => {
expect(entityQueryPolicies.worldPersistData).toMatchObject({
staleTime: 120000,
gcTime: 600000,
retry: 1,
refetchOnWindowFocus: false
});
});
test('user relation policies (mutualCounts, representedGroup)', () => {
expect(entityQueryPolicies.mutualCounts).toMatchObject({
staleTime: 120000,
gcTime: 600000,
retry: 1,
refetchOnWindowFocus: false
});
expect(entityQueryPolicies.representedGroup).toMatchObject({
staleTime: 60000,
gcTime: 300000,
retry: 1,
refetchOnWindowFocus: false
});
});
test('visits policy has longer staleTime for slow-changing data', () => {
expect(entityQueryPolicies.visits).toMatchObject({
staleTime: 300000,
gcTime: 900000,
retry: 1,
refetchOnWindowFocus: false
});
});
test('avatarStyles policy has very long staleTime for static config data', () => {
expect(entityQueryPolicies.avatarStyles).toMatchObject({
staleTime: 600000,
gcTime: 3600000,
retry: 1,
refetchOnWindowFocus: false
});
// Should outlive visits (which is already long-lived)
expect(entityQueryPolicies.avatarStyles.staleTime).toBeGreaterThan(
entityQueryPolicies.visits.staleTime
);
});
test('vrchatCredits policy has moderate staleTime for balance data', () => {
expect(entityQueryPolicies.vrchatCredits).toMatchObject({
staleTime: 120000,
gcTime: 600000,
retry: 1,
refetchOnWindowFocus: false
});
});
test('normalizes policy values to query options', () => {
const options = toQueryOptions(entityQueryPolicies.group);
@@ -157,4 +170,34 @@ describe('query policy configuration', () => {
refetchOnWindowFocus: false
});
});
test('toQueryOptions returns only the four query option fields', () => {
const options = toQueryOptions(entityQueryPolicies.user);
const keys = Object.keys(options);
expect(keys).toEqual([
'staleTime',
'gcTime',
'retry',
'refetchOnWindowFocus'
]);
});
test('all policies are frozen and immutable', () => {
for (const [, policy] of Object.entries(entityQueryPolicies)) {
expect(Object.isFrozen(policy)).toBe(true);
}
});
test('all policies have refetchOnWindowFocus disabled', () => {
for (const policy of Object.values(entityQueryPolicies)) {
expect(policy.refetchOnWindowFocus).toBe(false);
}
});
test('gcTime is always greater than staleTime for all policies', () => {
for (const [, policy] of Object.entries(entityQueryPolicies)) {
expect(policy.gcTime).toBeGreaterThan(policy.staleTime);
}
});
});