Merge branch 'relationships-chunk' into 'main'
Fetch relationships in chunks of 20 See merge request soapbox-pub/soapbox!3308
This commit is contained in:
commit
59698cff90
|
@ -1,6 +1,7 @@
|
||||||
import { HTTPError } from 'soapbox/api/HTTPError.ts';
|
import { HTTPError } from 'soapbox/api/HTTPError.ts';
|
||||||
import { importEntities } from 'soapbox/entity-store/actions.ts';
|
import { importEntities } from 'soapbox/entity-store/actions.ts';
|
||||||
import { Entities } from 'soapbox/entity-store/entities.ts';
|
import { Entities } from 'soapbox/entity-store/entities.ts';
|
||||||
|
import { relationshipSchema } from 'soapbox/schemas/relationship.ts';
|
||||||
import { selectAccount } from 'soapbox/selectors/index.ts';
|
import { selectAccount } from 'soapbox/selectors/index.ts';
|
||||||
import { isLoggedIn } from 'soapbox/utils/auth.ts';
|
import { isLoggedIn } from 'soapbox/utils/auth.ts';
|
||||||
import { getFeatures, parseVersion, PLEROMA } from 'soapbox/utils/features.ts';
|
import { getFeatures, parseVersion, PLEROMA } from 'soapbox/utils/features.ts';
|
||||||
|
@ -15,7 +16,7 @@ import {
|
||||||
|
|
||||||
import type { Map as ImmutableMap } from 'immutable';
|
import type { Map as ImmutableMap } from 'immutable';
|
||||||
import type { AppDispatch, RootState } from 'soapbox/store.ts';
|
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';
|
import type { History } from 'soapbox/types/history.ts';
|
||||||
|
|
||||||
const ACCOUNT_CREATE_REQUEST = 'ACCOUNT_CREATE_REQUEST';
|
const ACCOUNT_CREATE_REQUEST = 'ACCOUNT_CREATE_REQUEST';
|
||||||
|
@ -609,7 +610,7 @@ const expandFollowingFail = (id: string, error: unknown) => ({
|
||||||
});
|
});
|
||||||
|
|
||||||
const fetchRelationships = (accountIds: string[]) =>
|
const fetchRelationships = (accountIds: string[]) =>
|
||||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
async (dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
if (!isLoggedIn(getState)) return null;
|
if (!isLoggedIn(getState)) return null;
|
||||||
|
|
||||||
const loadedRelationships = getState().relationships;
|
const loadedRelationships = getState().relationships;
|
||||||
|
@ -621,15 +622,32 @@ const fetchRelationships = (accountIds: string[]) =>
|
||||||
|
|
||||||
dispatch(fetchRelationshipsRequest(newAccountIds));
|
dispatch(fetchRelationshipsRequest(newAccountIds));
|
||||||
|
|
||||||
return api(getState)
|
const results: Relationship[] = [];
|
||||||
.get(`/api/v1/accounts/relationships?${newAccountIds.map(id => `id[]=${id}`).join('&')}`)
|
|
||||||
.then((response) => response.json()).then((data) => {
|
try {
|
||||||
dispatch(importEntities(data, Entities.RELATIONSHIPS));
|
for (const ids of chunkArray(newAccountIds, 20)) {
|
||||||
dispatch(fetchRelationshipsSuccess(data));
|
const response = await api(getState).get('/api/v1/accounts/relationships', { searchParams: { id: ids } });
|
||||||
})
|
const json = await response.json();
|
||||||
.catch(error => dispatch(fetchRelationshipsFail(error)));
|
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[]) => ({
|
const fetchRelationshipsRequest = (ids: string[]) => ({
|
||||||
type: RELATIONSHIPS_FETCH_REQUEST,
|
type: RELATIONSHIPS_FETCH_REQUEST,
|
||||||
ids,
|
ids,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { MastodonResponse } from 'soapbox/api/MastodonResponse.ts';
|
||||||
import { Entities } from 'soapbox/entity-store/entities.ts';
|
import { Entities } from 'soapbox/entity-store/entities.ts';
|
||||||
import { useBatchedEntities } from 'soapbox/entity-store/hooks/useBatchedEntities.ts';
|
import { useBatchedEntities } from 'soapbox/entity-store/hooks/useBatchedEntities.ts';
|
||||||
import { useApi } from 'soapbox/hooks/useApi.ts';
|
import { useApi } from 'soapbox/hooks/useApi.ts';
|
||||||
|
@ -8,9 +9,19 @@ function useRelationships(listKey: string[], ids: string[]) {
|
||||||
const api = useApi();
|
const api = useApi();
|
||||||
const { isLoggedIn } = useLoggedIn();
|
const { isLoggedIn } = useLoggedIn();
|
||||||
|
|
||||||
function fetchRelationships(ids: string[]) {
|
async function fetchRelationships(ids: string[]) {
|
||||||
const q = ids.map((id) => `id[]=${id}`).join('&');
|
const results: Relationship[] = [];
|
||||||
return api.get(`/api/v1/accounts/relationships?${q}`);
|
|
||||||
|
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>(
|
const { entityMap: relationships, ...result } = useBatchedEntities<Relationship>(
|
||||||
|
@ -23,4 +34,12 @@ function useRelationships(listKey: string[], ids: string[]) {
|
||||||
return { relationships, ...result };
|
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 };
|
export { useRelationships };
|
Loading…
Reference in New Issue