Skip to content

Commit

Permalink
Feature: allow query options to be overridden at call time (#446)
Browse files Browse the repository at this point in the history
  • Loading branch information
kodiakhq[bot] authored Jun 2, 2022
2 parents 0e3bbd5 + e827992 commit be19e5d
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 20 deletions.
34 changes: 34 additions & 0 deletions src/datasource/__tests__/loaders.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,22 @@ describe(LoaderFactory, () => {
})
expect(await loader.load('zzz')).toMatchObject(dummyRow)
})

it('accepts a query options function', async () => {
const dummyRow = { id: 999, name: 'zzz', code: 'zzz' }
const getData = jest.fn((): [DummyRowType] => [dummyRow])
const loader = factory.create('name', { getData }, () => ({ limit: 1 }))
await loader.load('zzz')
expect(getData).toHaveBeenCalledWith(
expect.anything(),
expect.anything(),
expect.anything(),
expect.anything(),
expect.objectContaining({
limit: 1,
})
)
})
})

describe('createMulti', () => {
Expand Down Expand Up @@ -235,6 +251,24 @@ describe(LoaderFactory, () => {
]
`)
})

it('accepts a query options function', async () => {
const dummyRow = { id: 999, name: 'zzz', code: 'zzz' }
const getData = jest.fn((): [DummyRowType] => [dummyRow])
const loader = factory.createMulti(['name', 'code'], { getData }, () => ({
limit: 1,
}))
await loader.load({ name: 'zzz', code: 'zzz' })
expect(getData).toHaveBeenCalledWith(
expect.anything(),
expect.anything(),
expect.anything(),
expect.anything(),
expect.objectContaining({
limit: 1,
})
)
})
})

describe('auto-priming loaders', () => {
Expand Down
65 changes: 45 additions & 20 deletions src/datasource/loaders/LoaderFactory.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import DataLoader from 'dataloader'
import { QueryOptions } from '../queries/QueryBuilder'

import {
ExtendedDataLoader,
Expand Down Expand Up @@ -69,7 +70,8 @@ export default class LoaderFactory<TRowType> {
key: TColumnName,
options: LoaderOptions<TRowType> & {
multi: true
}
},
queryOptions?: () => QueryOptions<TRowType>
): ExtendedDataLoader<true, TRowType[TColumnName], TRowType[]>
public create<
TColumnName extends SearchableKeys<TRowType> & keyof TRowType & string
Expand All @@ -78,15 +80,17 @@ export default class LoaderFactory<TRowType> {
columnType: string,
options: LoaderOptions<TRowType> & {
multi: true
}
},
queryOptions?: () => QueryOptions<TRowType>
): ExtendedDataLoader<true, TRowType[TColumnName], TRowType[]>
public create<
TColumnName extends SearchableKeys<TRowType> & keyof TRowType & string
>(
key: TColumnName,
options?: LoaderOptions<TRowType> & {
multi?: false
}
},
queryOptions?: () => QueryOptions<TRowType>
): ExtendedDataLoader<false, TRowType[TColumnName], TRowType | undefined>
public create<
TColumnName extends SearchableKeys<TRowType> & keyof TRowType & string
Expand All @@ -95,24 +99,30 @@ export default class LoaderFactory<TRowType> {
columnType?: string,
options?: LoaderOptions<TRowType> & {
multi?: false
}
},
queryOptions?: () => QueryOptions<TRowType>
): ExtendedDataLoader<false, TRowType[TColumnName], TRowType | undefined>
public create<
TColumnName extends SearchableKeys<TRowType> & keyof TRowType & string,
TColType extends TRowType[TColumnName] & (string | number)
>(
key: TColumnName,
columnType?: string | LoaderOptions<TRowType>,
options?: LoaderOptions<TRowType>
options?: LoaderOptions<TRowType> | (() => QueryOptions<TRowType>),
queryOptions?: () => QueryOptions<TRowType>
): DataLoader<TColType, TRowType[] | TRowType | undefined> {
if (typeof options === 'function') {
queryOptions = options
options = undefined
}
if (typeof columnType === 'object') {
options = columnType
columnType = undefined
} else if (typeof options === 'undefined') {
options = {}
}

const getData = options.getData || this.getData
const actualOptions = options || {}

const getData = actualOptions.getData || this.getData

const type: string = columnType || this.options.columnTypes[key]

Expand All @@ -122,13 +132,16 @@ export default class LoaderFactory<TRowType> {
callbackFn,
autoPrime,
primeLoaders,
} = options
} = actualOptions

const loader = new DataLoader<
TColType,
TRowType[] | (TRowType | undefined)
>(async (args: readonly TColType[]) => {
const data = await getData<TColumnName>(args, key, type, loader, options)
const data = await getData<TColumnName>(args, key, type, loader, {
...actualOptions,
...queryOptions?.(),
})

data.forEach((row, idx, arr) => {
callbackFn && callbackFn(row, idx, arr)
Expand Down Expand Up @@ -172,7 +185,8 @@ export default class LoaderFactory<TRowType> {
key: TColumnNames,
options: LoaderOptions<TRowType, true> & {
multi: true
}
},
queryOptions?: () => QueryOptions<TRowType>
): ExtendedDataLoader<true, TBatchKey, TRowType[]>
public createMulti<
TColumnNames extends Array<
Expand All @@ -186,7 +200,8 @@ export default class LoaderFactory<TRowType> {
columnTypes: string[],
options: LoaderOptions<TRowType, true> & {
multi: true
}
},
queryOptions?: () => QueryOptions<TRowType>
): ExtendedDataLoader<true, TBatchKey, TRowType[]>
public createMulti<
TColumnNames extends Array<
Expand All @@ -199,7 +214,8 @@ export default class LoaderFactory<TRowType> {
key: TColumnNames,
options?: LoaderOptions<TRowType, true> & {
multi?: false
}
},
queryOptions?: () => QueryOptions<TRowType>
): ExtendedDataLoader<false, TBatchKey, TRowType | undefined>
public createMulti<
TColumnNames extends Array<
Expand All @@ -213,7 +229,8 @@ export default class LoaderFactory<TRowType> {
columnTypes?: string[],
options?: LoaderOptions<TRowType, true> & {
multi?: false
}
},
queryOptions?: () => QueryOptions<TRowType>
): ExtendedDataLoader<false, TBatchKey, TRowType | undefined>
public createMulti<
TColumnNames extends Array<
Expand All @@ -225,16 +242,21 @@ export default class LoaderFactory<TRowType> {
>(
keys: TColumnNames,
columnTypes?: string[] | LoaderOptions<TRowType, true>,
options?: LoaderOptions<TRowType, true>
options?: LoaderOptions<TRowType, true> | (() => QueryOptions<TRowType>),
queryOptions?: () => QueryOptions<TRowType>
): DataLoader<TBatchKey, TRowType[] | TRowType | undefined> {
if (typeof options === 'function') {
queryOptions = options
options = undefined
}
if (typeof columnTypes === 'object' && !Array.isArray(columnTypes)) {
options = columnTypes
columnTypes = undefined
} else if (typeof options === 'undefined') {
options = {}
}

const getData = options.getData || this.getDataMulti
const actualOptions = options || {}

const getData = actualOptions.getData || this.getDataMulti

const types: string[] =
columnTypes || keys.map((key) => this.options.columnTypes[key])
Expand All @@ -252,7 +274,7 @@ export default class LoaderFactory<TRowType> {
callbackFn,
autoPrime,
primeLoaders,
} = options
} = actualOptions

const loader = new DataLoader<
TBatchKey,
Expand All @@ -265,7 +287,10 @@ export default class LoaderFactory<TRowType> {
keys,
types,
loader,
options
{
...actualOptions,
...queryOptions?.(),
}
)

data.forEach((row, idx, arr) => {
Expand Down

0 comments on commit be19e5d

Please sign in to comment.