Skip to content

Commit

Permalink
add path helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
SKairinos committed Aug 13, 2024
1 parent cbe5326 commit ddd3842
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 12 deletions.
25 changes: 14 additions & 11 deletions src/utils/form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import type { TypedMutationTrigger } from "@reduxjs/toolkit/query/react"
import type { FieldValidator, FormikHelpers } from "formik"
import { ValidationError, type Schema, type ValidateOptions } from "yup"

import { excludeKeyPaths } from "./general"

export function isFormError(error: unknown): boolean {
return (
typeof error === "object" &&
Expand Down Expand Up @@ -31,12 +33,12 @@ export function setFormErrors(
}

export type SubmitFormOptions<
QueryArg,
QueryArg extends object,
ResultType,
FormValues extends QueryArg,
> = Partial<{
clean: (values: FormValues) => QueryArg
exclude: Array<keyof FormValues>
exclude: string[]
then: (
result: ResultType,
values: FormValues,
Expand All @@ -50,12 +52,19 @@ export type SubmitFormOptions<
finally: (values: FormValues, helpers: FormikHelpers<FormValues>) => void
}>

export type SubmitFormHandler<QueryArg, FormValues extends QueryArg> = (
export type SubmitFormHandler<
QueryArg extends object,
FormValues extends QueryArg,
> = (
values: FormValues,
helpers: FormikHelpers<FormValues>,
) => void | Promise<any>

export function submitForm<QueryArg, ResultType, FormValues extends QueryArg>(
export function submitForm<
QueryArg extends object,
ResultType,
FormValues extends QueryArg,
>(
trigger: TypedMutationTrigger<ResultType, QueryArg, any>,
options?: SubmitFormOptions<QueryArg, ResultType, FormValues>,
): SubmitFormHandler<QueryArg, FormValues> {
Expand All @@ -70,13 +79,7 @@ export function submitForm<QueryArg, ResultType, FormValues extends QueryArg>(
return (values, helpers) => {
let arg: QueryArg = clean ? clean(values) : values

if (exclude && exclude.length) {
arg = Object.fromEntries(
Object.entries(arg as object).filter(
([key]) => !exclude.includes(key as keyof FormValues),
),
) as QueryArg
}
if (exclude) arg = excludeKeyPaths(arg, exclude)

trigger(arg)
.unwrap()
Expand Down
23 changes: 22 additions & 1 deletion src/utils/general.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { getNestedProperty } from "./general"
import { excludeKeyPaths, getNestedProperty, withKeyPaths } from "./general"

// getNestedProperty

const PERSON = { father: { father: { name: "John" } } }

Expand All @@ -19,3 +21,22 @@ test("get a nested property that doesn't exist", () => {

expect(name).toBeUndefined()
})

// withKeyPaths

test("get the paths of nested keys", () => {
const obj = withKeyPaths({ a: 1, b: { c: 2, d: { e: 3 } } })

expect(obj).toMatchObject({ a: 1, b: { "b.c": 2, "b.d": { "b.d.e": 3 } } })
})

// excludeKeyPaths

test("exclude nested keys by their path", () => {
const obj = excludeKeyPaths({ a: 1, b: { c: 2, d: { e: 3 } } }, [
"b.c",
"b.d.e",
])

expect(obj).toMatchObject({ a: 1, b: { d: {} } })
})
38 changes: 38 additions & 0 deletions src/utils/general.ts
Original file line number Diff line number Diff line change
Expand Up @@ -453,3 +453,41 @@ export function getNestedProperty(

return value
}

export function withKeyPaths(obj: object, delimiter: string = "."): object {
function _withKeyPaths(obj: object, path: string[]) {
return Object.fromEntries(
Object.entries(obj).map(([key, value]) => {
const _path = [...path, key]

if (typeof value === "object") value = _withKeyPaths(value, _path)

return [_path.join(delimiter), value]
}),
)
}

return _withKeyPaths(obj, [])
}

export function excludeKeyPaths(
obj: object,
exclude: string[],
delimiter: string = ".",
): any {
function _excludeKeyPaths(obj: object, path: string[]) {
return Object.fromEntries(
Object.entries(obj)
.map(([key, value]) => {
const _path = [...path, key]

if (typeof value === "object") value = _excludeKeyPaths(value, _path)

return exclude.includes(_path.join(delimiter)) ? [] : [key, value]
})
.filter(entry => entry.length),
)
}

return exclude.length ? _excludeKeyPaths(obj, []) : obj
}

0 comments on commit ddd3842

Please sign in to comment.