{"version":3,"file":"useConnectionSpecPagination.mjs","names":["outArray: Array<T>","mostRecentItem:\n    | LoadedFragmentReference<TReadFromStore, Connection<TItem>>\n    | undefined"],"sources":["../../src/loadable-hooks/useConnectionSpecPagination.ts"],"sourcesContent":["import type { ItemCleanupPair } from '@isograph/disposable-types';\nimport {\n  UNASSIGNED_STATE,\n  useUpdatableDisposableState,\n} from '@isograph/react-disposable-state';\nimport type { ReferenceCountedPointer } from '@isograph/reference-counted-pointer';\nimport { createReferenceCountedPointer } from '@isograph/reference-counted-pointer';\nimport { useState } from 'react';\nimport { subscribeToAnyChange } from '../core/cache';\nimport type { FetchOptions } from '../core/check';\nimport type {\n  FragmentReference,\n  UnknownTReadFromStore,\n} from '../core/FragmentReference';\nimport { getPromiseState, readPromise } from '../core/PromiseWrapper';\nimport {\n  readButDoNotEvaluate,\n  type WithEncounteredRecords,\n} from '../core/read';\nimport type { LoadableField, ReaderAst } from '../core/reader';\nimport { getOrCreateCachedStartUpdate } from '../core/startUpdate';\nimport { useIsographEnvironment } from '../react/IsographEnvironmentProvider';\nimport { maybeUnwrapNetworkRequest } from '../react/maybeUnwrapNetworkRequest';\nimport { useSubscribeToMultiple } from '../react/useReadAndSubscribe';\n\nexport type UsePaginationReturnValue<\n  TReadFromStore extends UnknownTReadFromStore,\n  TItem,\n> =\n  | {\n      kind: 'Pending';\n      pendingFragment: FragmentReference<TReadFromStore, Connection<TItem>>;\n      results: ReadonlyArray<TItem>;\n    }\n  | {\n      kind: 'HasMoreRecords';\n      fetchMore: (\n        count: number,\n        fetchOptions?: FetchOptions<Connection<TItem>, never>,\n      ) => void;\n      results: ReadonlyArray<TItem>;\n    }\n  | {\n      kind: 'NoMoreRecords';\n      results: ReadonlyArray<TItem>;\n    };\n\ntype LoadedFragmentReferences<\n  TReadFromStore extends { parameters: object; data: object },\n  TItem,\n> = ReadonlyArray<LoadedFragmentReference<TReadFromStore, TItem>>;\n\ntype LoadedFragmentReference<\n  TReadFromStore extends { parameters: object; data: object },\n  TItem,\n> = ItemCleanupPair<\n  ReferenceCountedPointer<FragmentReference<TReadFromStore, TItem>>\n>;\n\nfunction flatten<T>(arr: ReadonlyArray<ReadonlyArray<T>>): ReadonlyArray<T> {\n  let outArray: Array<T> = [];\n  for (const subarr of arr) {\n    for (const item of subarr) {\n      outArray.push(item);\n    }\n  }\n  return outArray;\n}\n\nexport type PageInfo = {\n  readonly hasNextPage: boolean;\n  readonly endCursor: string | null;\n};\n\nexport type Connection<T> = {\n  readonly edges: ReadonlyArray<T> | null;\n  readonly pageInfo: PageInfo;\n};\n\ntype NonNullConnection<T> = {\n  readonly edges: ReadonlyArray<T>;\n  readonly pageInfo: PageInfo;\n};\n\nexport type UseConnectionSpecPaginationArgs = {\n  first: number;\n  after: string | null;\n};\n\nexport function useConnectionSpecPagination<\n  TReadFromStore extends UnknownTReadFromStore,\n  TItem,\n>(\n  loadableField: LoadableField<\n    TReadFromStore,\n    Connection<TItem>,\n    UseConnectionSpecPaginationArgs\n  >,\n  initialState?: PageInfo,\n): UsePaginationReturnValue<TReadFromStore, TItem> {\n  const networkRequestOptions = {\n    suspendIfInFlight: true,\n    throwOnNetworkError: true,\n  };\n  const { state, setState } =\n    useUpdatableDisposableState<\n      LoadedFragmentReferences<TReadFromStore, Connection<TItem>>\n    >();\n\n  const environment = useIsographEnvironment();\n\n  // TODO move this out of useSkipLimitPagination, and pass environment and networkRequestOptions\n  // as parameters (or recreate networkRequestOptions)\n  function readCompletedFragmentReferences(\n    completedReferences: FragmentReference<TReadFromStore, Connection<TItem>>[],\n  ): NonNullConnection<TItem> {\n    const results = completedReferences.map((fragmentReference, i) => {\n      const readerWithRefetchQueries = readPromise(\n        fragmentReference.readerWithRefetchQueries,\n      );\n\n      // invariant: readOutDataAndRecords.length === completedReferences.length\n      const data = readOutDataAndRecords[i]?.item;\n      if (data == null) {\n        throw new Error(\n          'Parameter data is unexpectedly null. This is indicative of a bug in Isograph.',\n        );\n      }\n\n      const firstParameter = {\n        data,\n        parameters: fragmentReference.variables,\n        ...(readerWithRefetchQueries.readerArtifact.hasUpdatable\n          ? {\n              startUpdate: getOrCreateCachedStartUpdate(\n                environment,\n                fragmentReference,\n                networkRequestOptions,\n              ),\n            }\n          : undefined),\n      };\n\n      if (\n        readerWithRefetchQueries.readerArtifact.kind !== 'EagerReaderArtifact'\n      ) {\n        throw new Error(\n          `@loadable field of kind \"${readerWithRefetchQueries.readerArtifact.kind}\" is not supported by useSkipLimitPagination`,\n        );\n      }\n\n      return readerWithRefetchQueries.readerArtifact.resolver(firstParameter);\n    });\n\n    const items = flatten(results.map((result) => result.edges ?? []));\n\n    return {\n      edges: items,\n      pageInfo: results[results.length - 1]?.pageInfo ?? {\n        endCursor: null,\n        hasNextPage: true,\n      },\n    };\n  }\n\n  function subscribeCompletedFragmentReferences(\n    completedReferences: FragmentReference<TReadFromStore, Connection<TItem>>[],\n  ) {\n    return completedReferences.map(\n      (\n        fragmentReference,\n        i,\n      ): {\n        records: WithEncounteredRecords<TReadFromStore>;\n        callback: (\n          updatedRecords: WithEncounteredRecords<TReadFromStore>,\n        ) => void;\n        fragmentReference: FragmentReference<TReadFromStore, Connection<TItem>>;\n        readerAst: ReaderAst<Connection<TItem>>;\n      } => {\n        maybeUnwrapNetworkRequest(\n          fragmentReference.networkRequest,\n          networkRequestOptions,\n        );\n\n        const readerWithRefetchQueries = readPromise(\n          fragmentReference.readerWithRefetchQueries,\n        );\n\n        const records = readOutDataAndRecords[i];\n        if (records == null) {\n          throw new Error(\n            'subscribeCompletedFragmentReferences records is unexpectedly null',\n          );\n        }\n\n        return {\n          fragmentReference,\n          readerAst: readerWithRefetchQueries.readerArtifact.readerAst,\n          records,\n          callback(_data) {\n            rerender({});\n          },\n        };\n      },\n    );\n  }\n\n  const getFetchMore =\n    (after: string | null) =>\n    (\n      count: number,\n      fetchOptions?: FetchOptions<Connection<TItem>, never>,\n    ): void => {\n      const loadedField = loadableField(\n        {\n          after: after,\n          first: count,\n        },\n        fetchOptions ?? {},\n      )[1]();\n      const newPointer = createReferenceCountedPointer(loadedField);\n      const clonedPointers = loadedReferences.map(([refCountedPointer]) => {\n        const clonedRefCountedPointer = refCountedPointer.cloneIfNotDisposed();\n        if (clonedRefCountedPointer == null) {\n          throw new Error(\n            'This reference counted pointer has already been disposed. \\\n            This is indicative of a bug in useSkipLimitPagination.',\n          );\n        }\n        return clonedRefCountedPointer;\n      });\n      clonedPointers.push(newPointer);\n\n      const totalItemCleanupPair: ItemCleanupPair<\n        ReadonlyArray<\n          ItemCleanupPair<\n            ReferenceCountedPointer<\n              FragmentReference<TReadFromStore, Connection<TItem>>\n            >\n          >\n        >\n      > = [\n        clonedPointers,\n        () => {\n          clonedPointers.forEach(([, dispose]) => {\n            dispose();\n          });\n        },\n      ];\n\n      setState(totalItemCleanupPair);\n    };\n\n  const [, rerender] = useState({});\n\n  const loadedReferences = state === UNASSIGNED_STATE ? [] : state;\n\n  const mostRecentItem:\n    | LoadedFragmentReference<TReadFromStore, Connection<TItem>>\n    | undefined = loadedReferences[loadedReferences.length - 1];\n  const mostRecentFragmentReference =\n    mostRecentItem?.[0].getItemIfNotDisposed();\n\n  if (mostRecentItem != null && mostRecentFragmentReference == null) {\n    throw new Error(\n      'FragmentReference is unexpectedly disposed. \\\n      This is indicative of a bug in Isograph.',\n    );\n  }\n\n  const networkRequestStatus =\n    mostRecentFragmentReference != null\n      ? {\n          mostRecentFragmentReference,\n          state: getPromiseState(mostRecentFragmentReference.networkRequest),\n        }\n      : null;\n\n  const slicedFragmentReferences =\n    networkRequestStatus?.state?.kind === 'Ok'\n      ? loadedReferences\n      : loadedReferences.slice(0, loadedReferences.length - 1);\n\n  const completedFragmentReferences = slicedFragmentReferences.map(\n    ([pointer]) => {\n      const fragmentReference = pointer.getItemIfNotDisposed();\n      if (fragmentReference == null) {\n        throw new Error(\n          'FragmentReference is unexpectedly disposed. \\\n            This is indicative of a bug in Isograph.',\n        );\n      }\n      return fragmentReference;\n    },\n  );\n\n  const readOutDataAndRecords = completedFragmentReferences.map(\n    (fragmentReference) =>\n      readButDoNotEvaluate(\n        environment,\n        fragmentReference,\n        networkRequestOptions,\n      ),\n  );\n\n  useSubscribeToMultiple<TReadFromStore>(\n    subscribeCompletedFragmentReferences(completedFragmentReferences),\n  );\n\n  if (networkRequestStatus == null) {\n    if (initialState?.hasNextPage ?? true) {\n      return {\n        kind: 'HasMoreRecords',\n        fetchMore: getFetchMore(initialState?.endCursor ?? null),\n        results: [],\n      };\n    } else {\n      return {\n        kind: 'NoMoreRecords',\n        results: [],\n      };\n    }\n  }\n\n  switch (networkRequestStatus.state.kind) {\n    case 'Pending': {\n      const unsubscribe = subscribeToAnyChange(environment, () => {\n        unsubscribe();\n        rerender({});\n      });\n\n      const results = readCompletedFragmentReferences(\n        completedFragmentReferences,\n      );\n      return {\n        results: results.edges,\n        kind: 'Pending',\n        pendingFragment: networkRequestStatus.mostRecentFragmentReference,\n      };\n    }\n    case 'Err': {\n      throw networkRequestStatus.state.error;\n    }\n    case 'Ok': {\n      const results = readCompletedFragmentReferences(\n        completedFragmentReferences,\n      );\n\n      if (results.pageInfo.hasNextPage) {\n        return {\n          kind: 'HasMoreRecords',\n          fetchMore: getFetchMore(results.pageInfo.endCursor),\n          results: results.edges,\n        };\n      } else {\n        return {\n          kind: 'NoMoreRecords',\n          results: results.edges,\n        };\n      }\n    }\n  }\n}\n"],"mappings":"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"}