Skip to content

Commit

Permalink
refactor: get rid of ValidatedData, simplify mutations
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielSchiavini committed Oct 21, 2024
1 parent 5cf3aea commit e8233c0
Show file tree
Hide file tree
Showing 9 changed files with 46 additions and 98 deletions.
47 changes: 12 additions & 35 deletions apps/main/src/entities/gauge/api/rewards-mutate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,46 +9,23 @@
* business logic and data fetching.
*/

import { type MutateFunction } from '@tanstack/react-query'
import { assertGaugeValidity } from '@/entities/gauge/lib'
import { GaugeQueryKeyType, type PoolMethodResult } from '@/entities/gauge/types'
import { AddRewardQuery, DepositRewardApproveQuery, DepositRewardQuery } from '@/entities/gauge/types'
import useStore from '@/store/useStore'

export const mutateAddRewardToken: MutateFunction<
PoolMethodResult<'gauge.addReward'>,
Error,
GaugeQueryKeyType<'addRewardToken'>
> = async (queryKey) => {
const [, { chainId }, , { poolId }, , , rewardTokenId, distributorId] = queryKey
const _valid = assertGaugeValidity({ chainId, poolId, rewardTokenId, distributorId })

const curve = useStore.getState().curve
const pool = curve.getPool(_valid.poolId)
return pool.gauge.addReward(_valid.rewardTokenId, _valid.distributorId)
export const mutateAddRewardToken = async ({ poolId, rewardTokenId, distributorId }: AddRewardQuery) => {
const { curve } = useStore.getState()
const pool = curve.getPool(poolId)
return pool.gauge.addReward(rewardTokenId, distributorId)
}

export const mutateDepositRewardApprove: MutateFunction<
PoolMethodResult<'gauge.depositRewardApprove'>,
Error,
GaugeQueryKeyType<'depositRewardApprove'>
> = async (queryKey) => {
const [, { chainId }, , { poolId }, , , rewardTokenId, amount] = queryKey
const _valid = assertGaugeValidity({ chainId, poolId, rewardTokenId, amount })

export const mutateDepositRewardApprove = async ({ poolId, rewardTokenId, amount }: DepositRewardApproveQuery) => {
const curve = useStore.getState().curve
const pool = curve.getPool(_valid.poolId)
return pool.gauge.depositRewardApprove(_valid.rewardTokenId, _valid.amount)
const pool = curve.getPool(poolId)
return pool.gauge.depositRewardApprove(rewardTokenId, amount)
}

export const mutateDepositReward: MutateFunction<
PoolMethodResult<'gauge.depositReward'>,
Error,
GaugeQueryKeyType<'depositReward'>
> = async (queryKey) => {
const [, { chainId }, , { poolId }, , , rewardTokenId, amount, epoch] = queryKey
const _valid = assertGaugeValidity({ chainId, poolId, rewardTokenId, amount, epoch })

const curve = useStore.getState().curve
const pool = curve.getPool(_valid.poolId)
return pool.gauge.depositReward(_valid.rewardTokenId, _valid.amount, _valid.epoch)
export const mutateDepositReward = async ({ poolId, rewardTokenId, amount, epoch }: DepositRewardQuery) => {
const { curve } = useStore.getState()
const pool = curve.getPool(poolId)
return pool.gauge.depositReward(rewardTokenId, amount, epoch)
}
1 change: 0 additions & 1 deletion apps/main/src/entities/gauge/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
export * from './reward-actions'
export * from './gauge-info'
export * from './validation'
12 changes: 7 additions & 5 deletions apps/main/src/entities/gauge/lib/reward-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ export const useAddRewardToken = ({
notifyNotification(txDescription, 'success')
}

queryClient.invalidateQueries({ queryKey: keys.distributors({ chainId, poolId }) })
queryClient.invalidateQueries({ queryKey: keys.isDepositRewardAvailable({ chainId, poolId }) })
return Promise.all([
queryClient.invalidateQueries({ queryKey: keys.distributors({ chainId, poolId }) }),
queryClient.invalidateQueries({ queryKey: keys.isDepositRewardAvailable({ chainId, poolId }) }),
])
},
onError: (error) => {
console.error('Error adding reward:', error)
Expand Down Expand Up @@ -83,7 +85,7 @@ export const useDepositRewardApprove = ({
const notifyMessage = t`Approve spending ${rewardTokenId ? tokensMapper[rewardTokenId]?.symbol : ''}`
notifyNotification(notifyMessage, 'success', 15000)
}
queryClient.invalidateQueries({
return queryClient.invalidateQueries({
queryKey: keys.depositRewardIsApproved({ chainId, poolId, rewardTokenId, amount }),
})
},
Expand Down Expand Up @@ -117,12 +119,12 @@ export const useDepositReward = ({

return useMutation({
...models.getDepositRewardMutation({ chainId, poolId }),
onSuccess: (resp, { rewardTokenId, amount, epoch }) => {
onSuccess: (resp, { rewardTokenId }) => {
if (resp) {
const txDescription = t`Deposited reward token ${rewardTokenId ? tokensMapper[rewardTokenId]?.symbol : ''}`
notifyNotification(txDescription, 'success', 15000)
}
queryClient.invalidateQueries({ queryKey: keys.isDepositRewardAvailable({ chainId, poolId }) })
return queryClient.invalidateQueries({ queryKey: keys.isDepositRewardAvailable({ chainId, poolId }) })
},
onError: (error) => {
console.error('Error depositing reward:', error)
Expand Down
17 changes: 0 additions & 17 deletions apps/main/src/entities/gauge/lib/validation.ts

This file was deleted.

14 changes: 7 additions & 7 deletions apps/main/src/entities/gauge/model/mutate-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
*/

import * as api from '@/entities/gauge/api'
import { gaugeKeys as keys } from '@/entities/gauge/model'
import { gaugeKeys as keys, gaugeValidationSuite } from '@/entities/gauge/model'
import type { AddRewardParams, DepositRewardApproveParams, DepositRewardParams } from '@/entities/gauge/types'
import { assertValidity } from '@/shared/lib/validation'
import { GaugeParams } from '@/shared/model/query'

export const getAddRewardTokenMutation = ({ chainId, poolId }: GaugeParams) => ({
mutationFn: async ({ rewardTokenId, distributorId }: AddRewardParams) =>
api.mutateAddRewardToken(keys.addRewardToken({ chainId, poolId, rewardTokenId, distributorId })),
mutationFn: async (params: AddRewardParams) => api.mutateAddRewardToken(assertValidity(gaugeValidationSuite, params)),
mutationKey: keys.addRewardToken({ chainId, poolId }),
meta: {
queryKeyFn: ({ rewardTokenId, distributorId }: AddRewardParams) =>
Expand All @@ -31,8 +31,8 @@ export const getAddRewardTokenMutation = ({ chainId, poolId }: GaugeParams) => (
})

export const getDepositRewardApproveMutation = ({ chainId, poolId }: GaugeParams) => ({
mutationFn: async ({ rewardTokenId, amount }: DepositRewardApproveParams) =>
api.mutateDepositRewardApprove(keys.depositRewardApprove({ chainId, poolId, rewardTokenId, amount })),
mutationFn: async (params: DepositRewardApproveParams) =>
api.mutateDepositRewardApprove(assertValidity(gaugeValidationSuite, params)),
mutationKey: keys.depositRewardApprove({ chainId, poolId }),
meta: {
queryKeyFn: ({ rewardTokenId, amount }: DepositRewardApproveParams) =>
Expand All @@ -41,8 +41,8 @@ export const getDepositRewardApproveMutation = ({ chainId, poolId }: GaugeParams
})

export const getDepositRewardMutation = ({ chainId, poolId }: GaugeParams) => ({
mutationFn: async ({ rewardTokenId, amount, epoch }: DepositRewardParams) =>
api.mutateDepositReward(keys.depositReward({ chainId, poolId, rewardTokenId, amount, epoch })),
mutationFn: async (params: DepositRewardParams) =>
api.mutateDepositReward(assertValidity(gaugeValidationSuite, params)),
mutationKey: keys.depositReward({ chainId, poolId }),
meta: {
queryKeyFn: ({ rewardTokenId, amount, epoch }: DepositRewardParams) =>
Expand Down
36 changes: 13 additions & 23 deletions packages/curve-lib/src/shared/lib/validation/lib.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,26 @@
import { create, enforce, only, type Suite } from 'vest'
import { extendEnforce } from './enforce-extension'
import { FieldName, ValidatedData } from './types'
import { FieldName, FieldsOf } from './types'

extendEnforce(enforce)

const getFieldsList = <T extends object, F extends Extract<keyof T, string>[] = Extract<keyof T, string>[]>(
data: T,
fields?: F
): F => fields && fields.length > 0 ? fields : (Object.keys(data) as F)

export function checkValidity<D extends object, S extends Suite<any, any>>(
export const checkValidity = <D extends object, S extends Suite<any, any>>(
suite: S,
data: D,
fields?: Extract<keyof D, string>[]
): boolean {
const fieldsList = getFieldsList(data, fields)
const result = suite(data, fieldsList)
return fieldsList.every((field) => result.getErrors(field).length === 0)
}
data: FieldsOf<D>,
fields?: FieldName<D>[]
): boolean => Object.keys(suite(data, fields).getErrors()).length === 0

export function assertValidity<D extends object, S extends Suite<any, any>>(
suite: S,
data: D,
fields?: Extract<keyof D, string>[]
): ValidatedData<D> {
const fieldsList = getFieldsList(data, fields)
const result = suite(data, fieldsList)
const errors = fieldsList.flatMap((field) => result.getErrors(field))
if (errors.length > 0) {
throw new Error('Validation failed: ' + errors.join(', '))
data: FieldsOf<D>,
fields?: FieldName<D>[]
): D {
const result = suite(data, fields)
const entries = Object.entries(result.getErrors())
if (entries.length > 0) {
throw new Error(`Validation failed: ${entries.map(([field, error]) => `${field}: ${error}`).join(', ')}`)
}
return data as ValidatedData<D>
return data as D
}

export const createValidationSuite = <
Expand Down
4 changes: 0 additions & 4 deletions packages/curve-lib/src/shared/lib/validation/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
export type ValidatedData<T extends object> = {
[K in keyof T]-?: NonNullable<T[K]>
}

export type FieldName<T> = Extract<keyof T, string>

export type FieldsOf<T> = {
Expand Down
11 changes: 6 additions & 5 deletions packages/curve-lib/src/shared/model/query/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@ import { assertValidity as sharedAssertValidity, checkValidity, FieldName, Field
import { REFRESH_INTERVAL } from '@/shared/model/time'
import { QueryFactoryInput, QueryFactoryOutput } from '../../types'

const extractQueryParams = (queryKey: readonly unknown[]) =>
(Object.fromEntries(queryKey.flatMap(i => i && typeof i === 'object' ? Object.entries(i) : [])))
export function getParamsFromQueryKey<TKey extends readonly unknown[], TParams, TQuery, TField>(queryKey: TKey, assertValidity: (data: TParams, fields?: TField[]) => TQuery) {
const queryParams = (Object.fromEntries(queryKey.flatMap(i => i && typeof i === 'object' ? Object.entries(i) : []))) as TParams
return assertValidity(queryParams)
}

export function queryFactory<
TQuery extends object,
TKey extends readonly unknown[],
TData,
TParams extends FieldsOf<TQuery> = FieldsOf<TQuery>,
TField extends FieldName<TParams> = FieldName<TParams>,
TField extends FieldName<TQuery> = FieldName<TQuery>,
TGroup extends string = string,
TCallback extends CB = CB<TQuery, TField[]>
>({
Expand All @@ -32,8 +34,7 @@ export function queryFactory<
queryKey: queryKey(params),
queryFn: ({ queryKey }: QueryFunctionContext<TKey>) => {
logQuery(queryKey)
const queryParams = extractQueryParams(queryKey) as TParams
const params = assertValidity(queryParams)
const params = getParamsFromQueryKey(queryKey, assertValidity)
return queryFn(params)
},
staleTime: staleTime ? REFRESH_INTERVAL[staleTime] : undefined,
Expand Down
2 changes: 1 addition & 1 deletion packages/curve-lib/src/shared/types/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type IsLiteralOrSingleKeyObject<T> =
? true
: false

// Recursively checks each element in the array
// Recursively checks each element in the tuple
type AreAllElementsLiteralOrSinglePropertyObject<T extends readonly unknown[]> = T extends readonly [
infer First,
...infer Rest,
Expand Down

0 comments on commit e8233c0

Please sign in to comment.