123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- import { ApolloClient, NormalizedCacheObject, HttpLink, InMemoryCache, DocumentNode } from '@apollo/client'
- import fetch from 'cross-fetch'
- import {
- GetBagConnection,
- GetBagConnectionQuery,
- GetBagConnectionQueryVariables,
- GetStorageBucketDetails,
- GetStorageBucketDetailsQuery,
- GetStorageBucketDetailsByWorkerIdQuery,
- GetStorageBucketDetailsByWorkerIdQueryVariables,
- GetStorageBucketDetailsQueryVariables,
- StorageBucketDetailsFragment,
- StorageBagDetailsFragment,
- DataObjectDetailsFragment,
- GetDataObjectConnectionQuery,
- GetDataObjectConnectionQueryVariables,
- GetDataObjectConnection,
- StorageBucketIdsFragment,
- GetStorageBucketsConnection,
- GetStorageBucketsConnectionQuery,
- GetStorageBucketsConnectionQueryVariables,
- } from './generated/queries'
- import { Maybe, StorageBagWhereInput } from './generated/schema'
- import logger from '../logger'
- /**
- * Defines query paging limits.
- */
- export const MAX_RESULTS_PER_QUERY = 1000
- type PaginationQueryVariables = {
- limit: number
- lastCursor?: Maybe<string>
- }
- type PaginationQueryResult<T = unknown> = {
- edges: { node: T }[]
- pageInfo: {
- hasNextPage: boolean
- endCursor?: Maybe<string>
- }
- }
- /**
- * Query node class helper. Incapsulates custom queries.
- *
- */
- export class QueryNodeApi {
- private apolloClient: ApolloClient<NormalizedCacheObject>
- public constructor(endpoint: string) {
- this.apolloClient = new ApolloClient({
- link: new HttpLink({ uri: endpoint, fetch }),
- cache: new InMemoryCache(),
- defaultOptions: {
- query: { fetchPolicy: 'no-cache', errorPolicy: 'none' },
- },
- })
- }
- /**
- * Get entity by unique input
- *
- * @param query - actual query
- * @param variables - query parameters
- * @param resultKey - hepls result parsing
- */
- protected async uniqueEntityQuery<
- QueryT extends { [k: string]: Maybe<Record<string, unknown>> | undefined },
- VariablesT extends Record<string, unknown>
- >(
- query: DocumentNode,
- variables: VariablesT,
- resultKey: keyof QueryT
- ): Promise<Required<QueryT>[keyof QueryT] | null> {
- const result = await this.apolloClient.query<QueryT, VariablesT>({
- query,
- variables,
- })
- if (result?.data === null) {
- return null
- }
- return result.data[resultKey]
- }
- // Get entities by "non-unique" input and return first result
- protected async firstEntityQuery<
- QueryT extends { [k: string]: unknown[] },
- VariablesT extends Record<string, unknown>
- >(query: DocumentNode, variables: VariablesT, resultKey: keyof QueryT): Promise<QueryT[keyof QueryT][number] | null> {
- const result = await this.apolloClient.query<QueryT, VariablesT>({
- query,
- variables,
- })
- if (result?.data === null) {
- return null
- }
- return result.data[resultKey][0]
- }
- protected async multipleEntitiesWithPagination<
- NodeT,
- QueryT extends { [k: string]: PaginationQueryResult<NodeT> },
- CustomVariablesT extends Record<string, unknown>
- >(
- query: DocumentNode,
- variables: CustomVariablesT,
- resultKey: keyof QueryT,
- itemsPerPage = MAX_RESULTS_PER_QUERY
- ): Promise<NodeT[]> {
- let hasNextPage = true
- let results: NodeT[] = []
- let lastCursor: string | undefined
- while (hasNextPage) {
- const paginationVariables = { limit: itemsPerPage, cursor: lastCursor }
- const queryVariables = { ...variables, ...paginationVariables }
- logger.debug(`Query - ${resultKey}`)
- const result = await this.apolloClient.query<QueryT, PaginationQueryVariables & CustomVariablesT>({
- query,
- variables: queryVariables,
- })
- if (!result?.data) {
- return results
- }
- const page = result.data[resultKey]
- results = results.concat(page.edges.map((e) => e.node))
- hasNextPage = page.pageInfo.hasNextPage
- lastCursor = page.pageInfo.endCursor || undefined
- }
- return results
- }
- /**
- * Query-node: get multiple entities
- *
- * @param query - actual query
- * @param variables - query parameters
- * @param resultKey - hepls result parsing
- */
- protected async multipleEntitiesQuery<
- QueryT extends { [k: string]: unknown[] },
- VariablesT extends Record<string, unknown>
- >(query: DocumentNode, variables: VariablesT, resultKey: keyof QueryT): Promise<QueryT[keyof QueryT] | null> {
- const result = await this.apolloClient.query<QueryT, VariablesT>({
- query,
- variables,
- })
- if (result?.data === null) {
- return null
- }
- return result.data[resultKey]
- }
- /**
- * Returns storage bucket IDs filtered by worker ID.
- *
- * @param workerId - worker ID
- */
- public async getStorageBucketDetailsByWorkerId(workerId: string): Promise<Array<StorageBucketIdsFragment>> {
- const result = await this.multipleEntitiesWithPagination<
- StorageBucketIdsFragment,
- GetStorageBucketDetailsByWorkerIdQuery,
- GetStorageBucketDetailsByWorkerIdQueryVariables
- >(GetStorageBucketsConnection, { workerId, limit: MAX_RESULTS_PER_QUERY }, 'storageBucketsConnection')
- if (!result) {
- return []
- }
- return result
- }
- /**
- * Returns storage bucket info by pages.
- *
- * @param ids - bucket IDs to fetch
- * @param offset - starting record of the page
- * @param limit - page size
- */
- public async getStorageBucketDetails(
- ids: string[],
- offset: number,
- limit: number
- ): Promise<Array<StorageBucketDetailsFragment>> {
- const result = await this.multipleEntitiesQuery<
- GetStorageBucketDetailsQuery,
- GetStorageBucketDetailsQueryVariables
- >(GetStorageBucketDetails, { offset, limit, ids }, 'storageBuckets')
- if (result === null) {
- return []
- }
- return result
- }
- /**
- * Returns storage bag info by pages for the given buckets.
- *
- * @param bucketIds - query filter: bucket IDs
- */
- public async getStorageBagsDetails(bucketIds: string[]): Promise<Array<StorageBagDetailsFragment>> {
- const result = await this.multipleEntitiesWithPagination<
- StorageBagDetailsFragment,
- GetBagConnectionQuery,
- GetBagConnectionQueryVariables
- >(GetBagConnection, { limit: MAX_RESULTS_PER_QUERY, bucketIds }, 'storageBagsConnection')
- if (!result) {
- return []
- }
- return result
- }
- /**
- * Returns data objects info by pages for the given bags.
- *
- * @param bagIds - query filter: bag IDs
- * @param offset - starting record of the page
- */
- public async getDataObjectDetails(bagIds: string[]): Promise<Array<DataObjectDetailsFragment>> {
- const input: StorageBagWhereInput = { id_in: bagIds }
- const result = await this.multipleEntitiesWithPagination<
- DataObjectDetailsFragment,
- GetDataObjectConnectionQuery,
- GetDataObjectConnectionQueryVariables
- >(GetDataObjectConnection, { limit: MAX_RESULTS_PER_QUERY, bagIds: input }, 'storageDataObjectsConnection')
- if (!result) {
- return []
- }
- return result
- }
- /**
- * Returns storage bucket IDs.
- *
- */
- public async getStorageBucketIds(): Promise<Array<StorageBucketIdsFragment>> {
- const result = await this.multipleEntitiesWithPagination<
- StorageBucketIdsFragment,
- GetStorageBucketsConnectionQuery,
- GetStorageBucketsConnectionQueryVariables
- >(GetStorageBucketsConnection, { limit: MAX_RESULTS_PER_QUERY }, 'storageBucketsConnection')
- if (!result) {
- return []
- }
- return result
- }
- }
|