Skip to content

Commit

Permalink
Divide COMS object search request to limit URL length
Browse files Browse the repository at this point in the history
  • Loading branch information
TimCsaky committed Aug 23, 2023
1 parent 62fe333 commit 5c9a930
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 6 deletions.
41 changes: 40 additions & 1 deletion frontend/src/services/objectService.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { comsAxios } from './interceptors';
import { setDispositionHeader } from '@/utils/utils';
import { ConfigService } from './index';

import type { AxiosRequestConfig } from 'axios';
import type { GetMetadataOptions, GetObjectTaggingOptions, MetadataPair, SearchObjectsOptions, Tag } from '@/types';
Expand Down Expand Up @@ -227,7 +228,45 @@ export default {
searchObjects(params: SearchObjectsOptions = {}, headers: any = {},) {
// remove objectId array if its first element is undefined
if (params.objectId && params.objectId[0] === undefined) delete params.objectId;
return comsAxios().get(PATH, { params: params, headers: headers });

if (params.objectId) {
/**
* split calls to COMS if query params (eg objectId's)
* will cause url length to excede 2000 characters
* see: https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
*
* TODO: consider creating a utils function
* eg: `divideParam(params, attr)`
* ... return Promise.all(divideParam(params, objectId).map(zparam => comsAxios().get(PATH, {params: zparam, headers: headers});
*/
const urlLimit = 2000;
// caculate number of characters taken by base url and query params other than objectId:
const { objectId: objectIds, ...otherParams } = params;
const url = new URL(`${new ConfigService().getConfig().coms.apiPath}${PATH}`);
url.search = new URLSearchParams(otherParams);
const otherCharacters = url.toString().length;

// number of allowed objectId's in each group - 48 chars for each objectId (&objectId[]=<uuid>)
const space = urlLimit - otherCharacters;
const groupSize = Math.floor(space / 48);

// loop through each group and push COMS result to `groups` array
const iterations = Math.ceil(objectIds.length / groupSize);
const groups = [];

for (let i = 0; i < iterations; i++) {
const ids = objectIds.slice(i * groupSize, ((i * groupSize) + groupSize));
groups.push(comsAxios().get(PATH, { params: { ...params, objectId: ids }, headers: headers }));
}

return Promise.all(groups)
.then((results) => ({ data: results.flatMap(result => result.data) }));
}

// else just call COMS once
else {
return comsAxios().get(PATH, { params: params, headers: headers });
}
},

/**
Expand Down
10 changes: 5 additions & 5 deletions frontend/src/store/objectStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ export const useObjectStore = defineStore('object', () => {
}

async function fetchObjects(
params: ObjectSearchPermissionsOptions = {},
tagset?: Array<Tag>,
params: ObjectSearchPermissionsOptions = {},
tagset?: Array<Tag>,
metadata?: Array<MetadataPair>) {
try {
appStore.beginIndeterminateLoading();
Expand All @@ -137,7 +137,7 @@ export const useObjectStore = defineStore('object', () => {
}
}

response = (await objectService.searchObjects({
response = await objectService.searchObjects({
bucketId: params.bucketId ? [params.bucketId] : undefined,
objectId: uniqueIds,
tagset: tagset ? tagset.reduce((acc, cur) => ({ ...acc, [cur.key]: cur.value }), {}) : undefined,
Expand All @@ -146,7 +146,7 @@ export const useObjectStore = defineStore('object', () => {
// TODO: Verify if needed after versioning implemented
deleteMarker: false,
latest: true
}, headers)).data;
}, headers).then(r => r.data);

// Remove old values matching search parameters
const matches = (x: COMSObject) => (
Expand All @@ -159,7 +159,7 @@ export const useObjectStore = defineStore('object', () => {
// Merge and assign
state.objects.value = difference.concat(response);

// Track all the object IDs in this bucket that the user would have access to in the table
// Track all the object IDs in this bucket that the user would have access to in the table
// (even if filters are applied)
if(!tagset?.length && !metadata?.length) {
state.unfilteredObjectIds.value = state.objects.value
Expand Down

0 comments on commit 5c9a930

Please sign in to comment.