Skip to content
This repository has been archived by the owner on Jan 6, 2025. It is now read-only.

Commit

Permalink
add TaggedRequest class (#574)
Browse files Browse the repository at this point in the history
  • Loading branch information
tim-smart authored Nov 21, 2023
1 parent 9653cf4 commit 2ed5f8e
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/spotty-gorillas-cry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@effect/schema": patch
---

add TaggedRequest class
65 changes: 65 additions & 0 deletions docs/modules/Schema.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ Added in v1.0.0
- [Class (interface)](#class-interface)
- [TaggedClass](#taggedclass)
- [TaggedError](#taggederror)
- [TaggedRequest](#taggedrequest)
- [TaggedRequest (namespace)](#taggedrequest-namespace)
- [Base (interface)](#base-interface)
- [ResultSchemas (interface)](#resultschemas-interface)
- [combinators](#combinators)
- [array](#array)
- [attachPropertySignature](#attachpropertysignature)
Expand Down Expand Up @@ -1159,6 +1163,67 @@ export declare const TaggedError: <Self>() => <Tag extends string, Fields extend
Added in v1.0.0
## TaggedRequest
**Signature**
```ts
export declare const TaggedRequest: <Self>() => <Tag extends string, Fields extends StructFields, EI, EA, AI, AA>(
tag: Tag,
failure: Schema<EI, EA>,
success: Schema<AI, AA>,
fields: Fields
) => [unknown] extends [Self]
? 'Missing `Self` generic - use `class Self extends TaggedRequest<Self>()("Tag", SuccessSchema, FailureSchema, { ... })`'
: Class<
Simplify<
{ readonly _tag: Tag } & {
readonly [K in Exclude<keyof Fields, FromOptionalKeys<Fields>>]: Schema.From<Fields[K]>
} & { readonly [K in FromOptionalKeys<Fields>]?: Schema.From<Fields[K]> | undefined }
>,
Simplify<
{ readonly _tag: Tag } & {
readonly [K in Exclude<keyof Fields, ToOptionalKeys<Fields>>]: Schema.To<Fields[K]>
} & { readonly [K in ToOptionalKeys<Fields>]?: Schema.To<Fields[K]> | undefined }
>,
Simplify<ToStruct<Fields>>,
Self,
Request.Request<EA, AA>
> &
TaggedRequest.ResultSchemas<EI, EA, AI, AA>
```
Added in v1.0.0
## TaggedRequest (namespace)
Added in v1.0.0
### Base (interface)
**Signature**
```ts
export interface Base<EI, EA, AI, AA, I, Req extends Request.Request<EA, AA>>
extends Schema<I, Req>,
TaggedRequest.ResultSchemas<EI, EA, AI, AA> {}
```

Added in v1.0.0

### ResultSchemas (interface)

**Signature**

```ts
export interface ResultSchemas<EI, EA, AI, AA> {
readonly Failure: Schema<EI, EA>
readonly Success: Schema<AI, AA>
}
```

Added in v1.0.0

# combinators

## array
Expand Down
59 changes: 59 additions & 0 deletions src/Schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import type { Pipeable } from "effect/Pipeable"
import { pipeArguments } from "effect/Pipeable"
import * as Predicate from "effect/Predicate"
import * as ReadonlyArray from "effect/ReadonlyArray"
import * as Request from "effect/Request"
import * as S from "effect/String"
import type { Equals, Simplify } from "effect/Types"
import type { Arbitrary } from "./Arbitrary.js"
Expand Down Expand Up @@ -3691,6 +3692,64 @@ export const TaggedError = <Self>() =>
)
}
/**
* @category classes
* @since 1.0.0
*/
export declare namespace TaggedRequest {
/**
* @category classes
* @since 1.0.0
*/
export interface Base<EI, EA, AI, AA, I, Req extends Request.Request<EA, AA>>
extends Schema<I, Req>, TaggedRequest.ResultSchemas<EI, EA, AI, AA>
{}
/**
* @category classes
* @since 1.0.0
*/
export interface ResultSchemas<EI, EA, AI, AA> {
readonly Failure: Schema<EI, EA>
readonly Success: Schema<AI, AA>
}
}
/**
* @category classes
* @since 1.0.0
*/
export const TaggedRequest =
<Self>() =>
<Tag extends string, Fields extends StructFields, EI, EA, AI, AA>(
tag: Tag,
failure: Schema<EI, EA>,
success: Schema<AI, AA>,
fields: Fields
): [unknown] extends [Self] ?
MissingSelfGeneric<"TaggedRequest", `"Tag", SuccessSchema, FailureSchema, `>
:
& Class<
Simplify<{ readonly _tag: Tag } & FromStruct<Fields>>,
Simplify<{ readonly _tag: Tag } & ToStruct<Fields>>,
Simplify<ToStruct<Fields>>,
Self,
Request.Request<EA, AA>
>
& TaggedRequest.ResultSchemas<EI, EA, AI, AA> =>
{
const fieldsWithTag = { ...fields, _tag: literal(tag) }
const Base = makeClass(
struct(fieldsWithTag),
fieldsWithTag,
Request.Class,
{ _tag: tag }
)
Base.Failure = failure
Base.Success = success
return Base
}
const makeClass = <I, A>(
selfSchema: Schema<I, A>,
selfFields: StructFields,
Expand Down
32 changes: 32 additions & 0 deletions test/Schema/Class.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Effect } from "effect"
import * as Data from "effect/Data"
import * as Equal from "effect/Equal"
import * as O from "effect/Option"
import * as Request from "effect/Request"
import { describe, expect, it } from "vitest"

class Person extends S.Class<Person>()({
Expand Down Expand Up @@ -237,4 +238,35 @@ describe("Schema/Class", () => {
expect(err._tag).toEqual("MyError")
expect(err.id).toEqual(1)
})

it("TaggedRequest", () => {
class MyRequest extends S.TaggedRequest<MyRequest>()("MyRequest", S.string, S.number, {
id: S.number
}) {}

let req = new MyRequest({ id: 1 })
expect(req._tag).toEqual("MyRequest")
expect(req.id).toEqual(1)
expect(Request.isRequest(req)).toEqual(true)

req = S.decodeSync(MyRequest)({ _tag: "MyRequest", id: 1 })
expect(req._tag).toEqual("MyRequest")
expect(req.id).toEqual(1)
expect(Request.isRequest(req)).toEqual(true)

S.decodeSync(MyRequest.Success)(123)
S.decodeSync(MyRequest.Failure)("fail")
})

it("TaggedRequest assignable to TaggedRequest.Base", () => {
class MyRequest extends S.TaggedRequest<MyRequest>()("MyRequest", S.string, S.number, {
id: S.number
}) {}

const makeCache = <EI, EA, AI, AA, I, Req extends Request.Request<EA, AA>>(
schema: S.TaggedRequest.Base<EI, EA, AI, AA, I, Req>
) => schema

makeCache(MyRequest)
})
})

0 comments on commit 2ed5f8e

Please sign in to comment.