Skip to content

Commit

Permalink
Merge pull request #113 from seasonedcc/update-readme
Browse files Browse the repository at this point in the history
Update README with type inferences and new Remix syntax
  • Loading branch information
gustavoguichard authored Sep 12, 2023
2 parents 5e878e5 + 6c9b86e commit 14b1e1b
Showing 1 changed file with 38 additions and 66 deletions.
104 changes: 38 additions & 66 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,15 @@ This documentation will use Node.JS imports by convention, just replace `domain-
## Create your first action with Remix

```tsx
import type { ActionFunction } from 'remix'
import type { DataFunctionArgs } from 'remix'
import { useActionData, redirect } from 'remix'
// You can also use the short version of makeDomainFunction: mdf
import { mdf, inputFromForm } from 'domain-functions'
import * as z from 'zod'

const schema = z.object({ number: z.coerce.number() })

export const action: ActionFunction = async ({ request }) => {
export async function action({ request }: DataFunctionArgs) {
const increment = mdf(schema)(({ number }) => number + 1)
const result = await increment(await inputFromForm(request))

Expand All @@ -121,7 +121,8 @@ export const action: ActionFunction = async ({ request }) => {
}

export default function Index() {
const actionData = useActionData()
const actionData = useActionData<typeof action>()
// ^? ErrorResult | null

return (
<Form method="post">
Expand Down Expand Up @@ -237,6 +238,7 @@ const alwaysFails = mdf(input, environment)(async () => {
})

const failedResult = await alwaysFails(someInput)
// ^? Result<never>
/*
failedResult = {
success: false,
Expand All @@ -255,6 +257,7 @@ const alwaysFails = mdf(input, environment)(async () => {
})

const failedResult = await alwaysFails(someInput)
// ^? Result<never>
/*
failedResult = {
success: false,
Expand Down Expand Up @@ -333,9 +336,10 @@ const b = mdf(z.object({ id: z.number() }))(({ id }) => id + 1)
const c = mdf(z.object({ id: z.number() }))(({ id }) => Boolean(id))

const results = await all(a, b, c)({ id: 1 })
// ^? Result<[string, number, boolean]>
```

For the example above, the result type will be `Result<[string, number, boolean]>`:
For the example above, the result will be:

```ts
{
Expand All @@ -358,6 +362,7 @@ const b = mdf(z.object({ id: z.number() }))(() => {
})

const results = await all(a, b)({ id: 1 })
// ^? Result<[never, never]>

/*{
success: false,
Expand All @@ -382,9 +387,10 @@ const b = mdf(z.object({}))(() => 2)
const c = mdf(z.object({}))(() => true)

const results = await collect({ a, b, c })({})
// ^? Result<{ a: string, b: number, c: boolean }>
```

For the example above, the result type will be `Result<{ a: string, b: number, c: boolean }>`:
For the example above, the result will be:

```ts
{
Expand Down Expand Up @@ -420,10 +426,10 @@ const b = mdf(z.object({}))(() => ({ resultB: 2 }))
const c = mdf(z.object({}))(async () => ({ resultC: true }))

const results = await merge(a, b, c)({})
// ^? Result<{ resultA: string, resultB: number, resultC: boolean }>
```

For the example above, the result type will be `Result<{ resultA: string, resultB: number, resultC: boolean }>`:

For the example above, the result will be:
```ts
{
success: true,
Expand All @@ -434,17 +440,6 @@ For the example above, the result type will be `Result<{ resultA: string, result
}
```

__Be mindful of__ each constituent domain function's return type. If any domain function returns something other than an object, the composite domain function will return an `ErrorResult`:

```ts
{
success: false,
errors: [{ message: 'Invalid data format returned from some domain functions' }],
inputErrors: [],
environmentErrors: [],
}
```

### first

`first` will create a composite domain function that will return the result of the first successful constituent domain function. It handles inputs and environments like the `all` function.
Expand All @@ -459,9 +454,10 @@ const b = mdf(
)(({ n }) => n - 1)

const result = await first(a, b)({ n: 1, operation: 'increment' })
// ^? Result<number>
```

For the example above, the result type will be `Result<number>`:
For the example above, the result will be:

```ts
{
Expand All @@ -484,7 +480,8 @@ const b = mdf(z.object({ operation: z.literal('B') }))(() => ({
}))

const result = await first(a, b)({ operation: 'A' })
// ^-- Result<{ resultA: string } | { resultB: string }>
// ^? Result<{ resultA: string } | { resultB: string }>

if (!result.success) return console.log('No function was successful')
if ('resultA' in result.data) return console.log('function A succeeded')
return console.log('function B succeeded')
Expand All @@ -501,6 +498,7 @@ const b = mdf(z.object({ id: z.number() }))(() => {
})

const result = await first(a, b)({ id: 1 })
// ^? Result<never>

/*{
success: false,
Expand Down Expand Up @@ -539,9 +537,10 @@ const c = mdf(z.object({ aBoolean: z.boolean() }))(
const d = pipe(a, b, c)

const result = await d({ aNumber: 1 })
// ^? Result<boolean>
```

For the example above, the result type will be `Result<boolean>`:
For the example above, the result will be:

```ts
{
Expand All @@ -567,9 +566,10 @@ const b = mdf(z.string())((aString) => aString === '1')
const c = sequence(a, b)

const result = await c(1)
// ^? Result<[string, boolean]>
```

For the example above, the result type will be `Result<[string, boolean]>`:
For the example above, the result will be:

```ts
{
Expand All @@ -596,10 +596,9 @@ const b = mdf(z.object({ aString: z.string() }))(
const c = map(sequence(a, b), mergeObjects)

const result = await c(1)
// ^? Result<{ aString: string, aBoolean: boolean }>
```

For the example above, the result type will be `Result<{ aString: string, aBoolean: boolean }>`.

### collectSequence

`collectSequence` is very similar to the `collect` function, except __it runs in the sequence of the keys' order like a `pipe`__.
Expand All @@ -618,9 +617,10 @@ const b = mdf(z.string())((aString) => aString === '1')
const c = collectSequence({ a, b })

const result = await c(1)
// ^? Result<{ a: string, b: boolean }>
```

For the example above, the result type will be `Result<{ a: string, b: boolean }>`:
For the example above, the result will be:

```ts
{
Expand All @@ -632,26 +632,6 @@ For the example above, the result type will be `Result<{ a: string, b: boolean }
}
```

If you'd rather have an object instead of a tuple (similar to the `merge` function), you can use the `map` and `mergeObjects` functions like so:

```ts
import { mergeObjects } from 'domain-functions'

const a = mdf(z.number())((aNumber) => ({
aString: String(aNumber)
}))
const b = mdf(z.object({ aString: z.string() }))(
({ aString }) => ({ aBoolean: aString === '1' })
)

const c = map(sequence(a, b), mergeObjects)

const result = await c(1)
```

For the example above, the result type will be `Result<{ aString: string, aBoolean: boolean }>`.


### branch

Use `branch` to add conditional logic to your domain functions' compositions.
Expand All @@ -673,8 +653,9 @@ const findUserByIdOrEmail = branch(
(output) => (typeof output === "number" ? findUserById : findUserByEmail),
)
const result = await findUserByIdOrEmail({ id: 1 })
// ^? Result<User>
```
For the example above, the result type will be `Result<User>`:
For the example above, the result will be:
```ts
{
success: true,
Expand All @@ -701,6 +682,7 @@ const findUserByIdOrEmail = branch(
throw new Error("Invalid input")
},
)
// ^? DomainFunction<never>
```
For the example above, the result type will be `ErrorResult`:
```ts
Expand Down Expand Up @@ -738,9 +720,10 @@ const fetchFullName = pipe(
)

const result = fetchFullName({ userId: 2 })
// ^? Result<string>
```

For the example above, the result type will be `Result<string>` and its value something like this:
For the example above, the result will be something like this:

```ts
{
Expand Down Expand Up @@ -804,10 +787,7 @@ const domainFunctionA = mdf(
)(async ({ id }) => {
const valueB = await fromSuccess(domainFunctionB)({ userId: id })
// do something else
return {
valueA,
valueB,
}
return { valueA, valueB }
})
```

Expand All @@ -822,11 +802,11 @@ Object properties from the rightmost object will take precedence over the leftmo
const a = { a: 1, b: 2 }
const b = { b: '3', c: '4' }
const result = mergeObjects([a, b])
// ^? { a: number, b: string, c: string }
```
The resulting object will be:
```ts
{ a: 1, b: '3', c: '4' }
// inferred as { a: number, b: string, c: string }
```


Expand All @@ -841,7 +821,7 @@ The resulting object will be:
const fn = mdf()(async () => '')

type Data = UnpackData<typeof fn>
// Data = string
// ^? string
```
### UnpackSuccess
Expand All @@ -852,8 +832,8 @@ type Data = UnpackData<typeof fn>
const fn = mdf()(async () => '')

type Success = UnpackSuccess<typeof fn>
// Success = { success: true, data: string, errors: [], inputErrors: [], environmentErrors: [] }
// Which is the same as: SuccessResult<string>
// ^? SuccessResult<string>
// Which is the same as: { success: true, data: string, errors: [], inputErrors: [], environmentErrors: [] }
```
### UnpackResult
Expand All @@ -863,19 +843,11 @@ type Success = UnpackSuccess<typeof fn>
const fn = mdf()(async () => '')

type Result = UnpackResult<typeof fn>
/*
Result =
| { success: true, data: string, errors: [], inputErrors: [], environmentErrors: [], }
| { success: false, errors: { message: string }[], inputErrors: SchemaError[], environmentErrors: SchemaError[] }
* Which is the same as:
Result<string>
* Which is the same as:
SuccessResult<string> | ErrorResult
*/
// ^? Result<string>
// Which is the same as: { success: true, data: string, errors: [], inputErrors: [], environmentErrors: [], } | { success: false, errors: { message: string }[], inputErrors: SchemaError[], environmentErrors: SchemaError[] }
// Or the same as: SuccessResult<string> | ErrorResult
```
## Extracting input values for domain functions
We export some functions to help you extract values out of your requests before sending them as user input.
Expand Down

0 comments on commit 14b1e1b

Please sign in to comment.