import type { Document , Model } from 'mongoose' ; import { prepareConnectionResolver , ConnectionResolverOpts as _ConnectionResolverOpts , ConnectionSortMapOpts as _ConnectionSortMapOpts , ConnectionTArgs , } from 'graphql-compose-connection' ; import type { Resolver , ObjectTypeComposer , InterfaceTypeComposer } from 'graphql-compose' ; import { CountResolverOpts , count } from './count' ; import { FindManyResolverOpts , findMany } from './findMany' ; import { getUniqueIndexes , extendByReversedIndexes , IndexT } from '../utils/getIndexesFromModel' ; /**
 * Allows customization of the generated `connection` resolver.
 *
 * It is based on the `ConnectionResolverOpts` from: https://github.com/graphql-compose/graphql-compose-connection
 * With the following changes:
 * - `sort` prop is optional - when not provided derived from existing model indexes
 * - `findManyResolver` prop is removed - use the optional `findManyOpts` to customize the internally created `findMany` resolver
 * - `countResolver` prop is removed - use the optional `countOpts` to customize the internally created `count` resolver
 */ export type ConnectionResolverOpts < TContext = any > = Omit < _ConnectionResolverOpts < TContext > , 'countResolver' | 'findManyResolver' | 'sort' > & { findManyResolver ? : Resolver ; countResolver ? : Resolver ; countOpts ? : CountResolverOpts ; findManyOpts ? : FindManyResolverOpts ; sort ? : _ConnectionSortMapOpts ; } ; export function connection < TSource = any , TContext = any , TDoc extends Document = any > ( model , tc , opts ? ) { const uniqueIndexes = extendByReversedIndexes ( getUniqueIndexes ( model ) , { reversedFirst : true , } ) ; const sortConfigs = { } as Record < string , any > ; uniqueIndexes . forEach ( ( indexData ) => { const keys = Object . keys ( indexData ) ; let name = keys . join ( '__' ) . toUpperCase ( ) . replace ( /[^_a-zA-Z0-9]/i , '__' ) ; if ( indexData [ keys [ 0 ] ] === 1 ) { name = `${ name }_ASC` ; } else if ( indexData [ keys [ 0 ] ] === - 1 ) { name = `${ name }_DESC` ; } sortConfigs [ name ] = { value : indexData , cursorFields : keys , beforeCursorQuery : ( rawQuery , cursorData ) => { prepareCursorQuery ( rawQuery , cursorData , keys , indexData , '$lt' , '$gt' ) ; } , afterCursorQuery : ( rawQuery , cursorData ) => { prepareCursorQuery ( rawQuery , cursorData , keys , indexData , '$gt' , '$lt' ) ; } , } ; } ) ; const { findManyOpts , countOpts , findManyResolver , countResolver , ... restOpts } = opts || { } ; return prepareConnectionResolver < any , any > ( tc , { findManyResolver : findManyResolver || findMany ( model , tc , findManyOpts ) , countResolver : countResolver || count ( model , tc , countOpts ) , sort : sortConfigs , ... restOpts , } ) ; } export function prepareCursorQuery ( rawQuery , cursorData , indexKeys , indexData , nextOper , prevOper ) { if ( indexKeys . length === 1 ) { const k = indexKeys [ 0 ] ; if ( ! rawQuery [ k ] ) rawQuery [ k ] = { } ; if ( indexData [ k ] === 1 ) { rawQuery [ k ] [ nextOper ] = cursorData [ k ] ; } else { rawQuery [ k ] [ prevOper ] = cursorData [ k ] ; } } else { const orCriteries = [ ] ; for ( let i = indexKeys . length - 1 ; i >= 0 ; i -- ) { const criteria = { } as Record < string , any > ; indexKeys . forEach ( ( k , ii ) => { if ( ii < i ) { criteria [ k ] = cursorData [ k ] ; } else if ( ii === i ) { if ( indexData [ k ] === 1 ) { criteria [ k ] = { [ nextOper ] : cursorData [ k ] } ; } else { criteria [ k ] = { [ prevOper ] : cursorData [ k ] } ; } } } ) ; orCriteries . push ( criteria ) ; } rawQuery . $or = orCriteries ; } }