Merge branch 'relationships-chunk' into 'main'

Fetch relationships in chunks of 20

See merge request soapbox-pub/soapbox!3308
This commit is contained in:
Alex Gleason 2024-12-28 23:13:15 +00:00
commit 59698cff90
2 changed files with 49 additions and 12 deletions

View File

@ -1,6 +1,7 @@
import { HTTPError } from 'soapbox/api/HTTPError.ts';
import { importEntities } from 'soapbox/entity-store/actions.ts';
import { Entities } from 'soapbox/entity-store/entities.ts';
import { relationshipSchema } from 'soapbox/schemas/relationship.ts';
import { selectAccount } from 'soapbox/selectors/index.ts';
import { isLoggedIn } from 'soapbox/utils/auth.ts';
import { getFeatures, parseVersion, PLEROMA } from 'soapbox/utils/features.ts';
@ -15,7 +16,7 @@ import {
import type { Map as ImmutableMap } from 'immutable';
import type { AppDispatch, RootState } from 'soapbox/store.ts';
import type { APIEntity, Status } from 'soapbox/types/entities.ts';
import type { APIEntity, Relationship, Status } from 'soapbox/types/entities.ts';
import type { History } from 'soapbox/types/history.ts';
const ACCOUNT_CREATE_REQUEST = 'ACCOUNT_CREATE_REQUEST';
@ -609,7 +610,7 @@ const expandFollowingFail = (id: string, error: unknown) => ({
});
const fetchRelationships = (accountIds: string[]) =>
(dispatch: AppDispatch, getState: () => RootState) => {
async (dispatch: AppDispatch, getState: () => RootState) => {
if (!isLoggedIn(getState)) return null;
const loadedRelationships = getState().relationships;
@ -621,15 +622,32 @@ const fetchRelationships = (accountIds: string[]) =>
dispatch(fetchRelationshipsRequest(newAccountIds));
return api(getState)
.get(`/api/v1/accounts/relationships?${newAccountIds.map(id => `id[]=${id}`).join('&')}`)
.then((response) => response.json()).then((data) => {
dispatch(importEntities(data, Entities.RELATIONSHIPS));
dispatch(fetchRelationshipsSuccess(data));
})
.catch(error => dispatch(fetchRelationshipsFail(error)));
const results: Relationship[] = [];
try {
for (const ids of chunkArray(newAccountIds, 20)) {
const response = await api(getState).get('/api/v1/accounts/relationships', { searchParams: { id: ids } });
const json = await response.json();
const data = relationshipSchema.array().parse(json);
results.push(...data);
}
dispatch(importEntities(results, Entities.RELATIONSHIPS));
dispatch(fetchRelationshipsSuccess(results));
} catch (error) {
dispatch(fetchRelationshipsFail(error));
}
};
function* chunkArray<T>(array: T[], chunkSize: number): Iterable<T[]> {
if (chunkSize <= 0) throw new Error('Chunk size must be greater than zero.');
for (let i = 0; i < array.length; i += chunkSize) {
yield array.slice(i, i + chunkSize);
}
}
const fetchRelationshipsRequest = (ids: string[]) => ({
type: RELATIONSHIPS_FETCH_REQUEST,
ids,

View File

@ -1,3 +1,4 @@
import { MastodonResponse } from 'soapbox/api/MastodonResponse.ts';
import { Entities } from 'soapbox/entity-store/entities.ts';
import { useBatchedEntities } from 'soapbox/entity-store/hooks/useBatchedEntities.ts';
import { useApi } from 'soapbox/hooks/useApi.ts';
@ -8,9 +9,19 @@ function useRelationships(listKey: string[], ids: string[]) {
const api = useApi();
const { isLoggedIn } = useLoggedIn();
function fetchRelationships(ids: string[]) {
const q = ids.map((id) => `id[]=${id}`).join('&');
return api.get(`/api/v1/accounts/relationships?${q}`);
async function fetchRelationships(ids: string[]) {
const results: Relationship[] = [];
for (const id of chunkArray(ids, 20)) {
const response = await api.get('/api/v1/accounts/relationships', { searchParams: { id } });
const json = await response.json();
results.push(...json);
}
return new MastodonResponse(JSON.stringify(results), {
headers: { 'Content-Type': 'application/json' },
});
}
const { entityMap: relationships, ...result } = useBatchedEntities<Relationship>(
@ -23,4 +34,12 @@ function useRelationships(listKey: string[], ids: string[]) {
return { relationships, ...result };
}
function* chunkArray<T>(array: T[], chunkSize: number): Iterable<T[]> {
if (chunkSize <= 0) throw new Error('Chunk size must be greater than zero.');
for (let i = 0; i < array.length; i += chunkSize) {
yield array.slice(i, i + chunkSize);
}
}
export { useRelationships };