feathers-graph-populate
Version:
Add lightning fast, GraphQL-like populates to your FeathersJS API.
107 lines (89 loc) • 2.89 kB
text/typescript
import { _ } from '@feathersjs/commons'
const { each } = _
import _get from 'lodash/get.js'
import type { AnyData, GraphPopulateHook, GraphPopulateHookMap } from '../types'
export function convertHookData(
obj: GraphPopulateHook | AnyData | unknown[],
): Partial<GraphPopulateHookMap> {
let hook: Partial<GraphPopulateHookMap> = {}
if (Array.isArray(obj)) {
hook = { all: obj }
} else if (typeof obj !== 'object') {
hook = { all: [obj] }
} else {
each(obj, function (value, key) {
hook[key] = !Array.isArray(value) ? [value] : value
})
}
return hook
}
// eslint-disable-next-line
export function getHooks(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
app: any,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
service: any,
type: string,
method: string,
appLast = false,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
): any[] {
const appHooks = _get(app, ['__hooks', type, method]) || []
const serviceHooks = _get(service, ['__hooks', type, method]) || []
return appLast ? [...serviceHooks, ...appHooks] : [...appHooks, ...serviceHooks]
}
// eslint-disable-next-line
export function enableHooks(obj: any, methods: string[], types: string[]): AnyData {
if (typeof obj.hooks === 'function') {
return obj
}
const hookData: Partial<{
before: Partial<GraphPopulateHookMap>
after: Partial<GraphPopulateHookMap>
error: Partial<GraphPopulateHookMap>
}> = {}
types.forEach((type) => {
// Initialize properties where hook functions are stored
hookData[type] = {}
})
// Add non-enumerable `__hooks` property to the object
Object.defineProperty(obj, '__hooks', {
configurable: true,
value: hookData,
writable: true,
})
return Object.assign(obj, {
hooks(
allHooks:
| Partial<{
before: Partial<GraphPopulateHookMap>
after: Partial<GraphPopulateHookMap>
error: Partial<GraphPopulateHookMap>
}>
| GraphPopulateHook
| GraphPopulateHook[],
) {
each(allHooks, (current: GraphPopulateHook | AnyData | unknown[], type) => {
if (!this.__hooks[type]) {
throw new Error(`'${type}' is not a valid hook type`)
}
const hooks = convertHookData(current)
/*each(hooks, (_value, method) => {
if (method !== 'all' && methods.indexOf(method) === -1) {
throw new Error(`'${method}' is not a valid hook method`)
}
})*/
methods.forEach((method) => {
const currentHooks = this.__hooks[type][method] || (this.__hooks[type][method] = [])
if (hooks.all) {
currentHooks.push(...hooks.all)
}
if (hooks[method]) {
currentHooks.push(...hooks[method])
}
})
})
return this
},
})
}