diff --git a/.changeset/mean-badgers-grab.md b/.changeset/mean-badgers-grab.md new file mode 100644 index 000000000..3c586f0aa --- /dev/null +++ b/.changeset/mean-badgers-grab.md @@ -0,0 +1,5 @@ +--- +"@effect/schema": patch +--- + +added filters for Duration diff --git a/README.md b/README.md index 65f5dd969..8b157c617 100644 --- a/README.md +++ b/README.md @@ -952,6 +952,19 @@ S.BigDecimal.pipe(S.negativeBigDecimal()); S.BigDecimal.pipe(S.nonPositiveBigDecimal()); ``` +### Duration filters + +```ts +import * as S from "@effect/schema/Schema"; +import * as Duration from "effect/BigDecimal"; + +S.Duration.pipe(S.greaterThanDuration("5 seconds")); +S.Duration.pipe(S.greaterThanOrEqualToDuration("5 seconds")); +S.Duration.pipe(S.lessThanDuration("5 seconds")); +S.Duration.pipe(S.lessThanOrEqualToDuration("5 seconds")); +S.Duration.pipe(S.betweenDuration("5 seconds", "10 seconds")); +``` + ### Array filters ```ts @@ -2118,6 +2131,75 @@ parse("0"); // BigDecimal(0) parse("3"); // BigDecimal(-3) ``` +### Duration transformations + +#### Duration + +Converts an hrtime(i.e. `[seconds: number, nanos: number]`) into a `Duration`. + +```ts +import * as S from "@effect/schema/Schema"; +import * as Duration from "effect/Duration"; + +// $ExpectType Schema +const schema = S.Duration; + +const parse = S.parseSync(schema); +parse([0, 0]); // 0 seconds +parse([5000, 0]); // 5 seconds +``` + +#### DurationFromNumber + +Converts a `number` into a `Duration` where the number represents the number of milliseconds. + +```ts +import * as S from "@effect/schema/Schema"; +import * as Duration from "effect/Duration"; + +// $ExpectType Schema +const schema = S.DurationFromNumber; + +const parse = S.parseSync(schema); +parse(0); // 0 seconds +parse(5000); // 5 seconds +``` + +#### DurationFromBigint + +Converts a `bigint` into a `Duration` where the number represents the number of nanoseconds. + +```ts +import * as S from "@effect/schema/Schema"; +import * as Duration from "effect/Duration"; + +// $ExpectType Schema +const schema = S.DurationFromBigint; + +const parse = S.parseSync(schema); +parse(0n); // 0 seconds +parse(5000000000n); // 5 seconds +``` + +#### clampDuration + +Clamps a `Duration` between a minimum and a maximum value. + +```ts +import * as S from "@effect/schema/Schema"; +import * as Duration from "effect/Duration"; + +// $ExpectType Schema +const schema = S.DurationFromSelf.pipe( + S.clampDuration("5 seconds", "10 seconds") +); + +const parse = S.parseSync(schema); +parse(Duration.decode("2 seconds")); // 5 seconds +parse(Duration.decode("6 seconds")); // 6 seconds +parse(Duration.decode("11 seconds")); // 10 seconds +``` + ### Symbol transformations #### symbol diff --git a/docs/modules/Schema.ts.md b/docs/modules/Schema.ts.md index 917c0065c..92f9e9fab 100644 --- a/docs/modules/Schema.ts.md +++ b/docs/modules/Schema.ts.md @@ -48,9 +48,20 @@ Added in v1.0.0 - [dateFromString](#datefromstring-1) - [Duration constructors](#duration-constructors) - [Duration](#duration) + - [DurationFromMillis](#durationfrommillis) + - [DurationFromNanos](#durationfromnanos) - [DurationFromSelf](#durationfromself) +- [Duration filters](#duration-filters) + - [betweenDuration](#betweenduration) + - [greaterThanDuration](#greaterthanduration) + - [greaterThanOrEqualToDuration](#greaterthanorequaltoduration) + - [lessThanDuration](#lessthanduration) + - [lessThanOrEqualToDuration](#lessthanorequaltoduration) - [Duration transformations](#duration-transformations) + - [clampDuration](#clampduration) - [durationFromHrTime](#durationfromhrtime) + - [durationFromMillis](#durationfrommillis-1) + - [durationFromNanos](#durationfromnanos-1) - [Either transformations](#either-transformations) - [EitherFrom (type alias)](#eitherfrom-type-alias) - [either](#either) @@ -270,6 +281,7 @@ Added in v1.0.0 - [BetweenBigDecimalTypeId](#betweenbigdecimaltypeid) - [BetweenBigintTypeId](#betweenbiginttypeid) - [BetweenBigintTypeId (type alias)](#betweenbiginttypeid-type-alias) + - [BetweenDurationTypeId](#betweendurationtypeid) - [BetweenTypeId](#betweentypeid) - [BetweenTypeId (type alias)](#betweentypeid-type-alias) - [BrandTypeId](#brandtypeid) @@ -278,9 +290,11 @@ Added in v1.0.0 - [GreaterThanBigDecimalTypeId](#greaterthanbigdecimaltypeid) - [GreaterThanBigintTypeId](#greaterthanbiginttypeid) - [GreaterThanBigintTypeId (type alias)](#greaterthanbiginttypeid-type-alias) + - [GreaterThanDurationTypeId](#greaterthandurationtypeid) - [GreaterThanOrEqualToBigDecimalTypeId](#greaterthanorequaltobigdecimaltypeid) - [GreaterThanOrEqualToBigintTypeId](#greaterthanorequaltobiginttypeid) - [GreaterThanOrEqualToBigintTypeId (type alias)](#greaterthanorequaltobiginttypeid-type-alias) + - [GreaterThanOrEqualToDurationTypeId](#greaterthanorequaltodurationtypeid) - [GreaterThanOrEqualToTypeId](#greaterthanorequaltotypeid) - [GreaterThanOrEqualToTypeId (type alias)](#greaterthanorequaltotypeid-type-alias) - [GreaterThanTypeId](#greaterthantypeid) @@ -297,9 +311,11 @@ Added in v1.0.0 - [LessThanBigDecimalTypeId](#lessthanbigdecimaltypeid) - [LessThanBigintTypeId](#lessthanbiginttypeid) - [LessThanBigintTypeId (type alias)](#lessthanbiginttypeid-type-alias) + - [LessThanDurationTypeId](#lessthandurationtypeid) - [LessThanOrEqualToBigDecimalTypeId](#lessthanorequaltobigdecimaltypeid) - [LessThanOrEqualToBigintTypeId](#lessthanorequaltobiginttypeid) - [LessThanOrEqualToBigintTypeId (type alias)](#lessthanorequaltobiginttypeid-type-alias) + - [LessThanOrEqualToDurationTypeId](#lessthanorequaltodurationtypeid) - [LessThanOrEqualToTypeId](#lessthanorequaltotypeid) - [LessThanOrEqualToTypeId (type alias)](#lessthanorequaltotypeid-type-alias) - [LessThanTypeId](#lessthantypeid) @@ -710,6 +726,32 @@ export declare const Duration: Schema +``` + +Added in v1.0.0 + +## DurationFromNanos + +A schema that transforms a `bigint` tuple into a `Duration`. +Treats the value as the number of nanoseconds. + +**Signature** + +```ts +export declare const DurationFromNanos: Schema +``` + +Added in v1.0.0 + ## DurationFromSelf **Signature** @@ -720,8 +762,91 @@ export declare const DurationFromSelf: Schema( + minimum: Duration.DurationInput, + maximum: Duration.DurationInput, + options?: FilterAnnotations | undefined +) => (self: Schema) => Schema +``` + +Added in v1.0.0 + +## greaterThanDuration + +**Signature** + +```ts +export declare const greaterThanDuration: ( + min: Duration.DurationInput, + options?: FilterAnnotations | undefined +) => (self: Schema) => Schema +``` + +Added in v1.0.0 + +## greaterThanOrEqualToDuration + +**Signature** + +```ts +export declare const greaterThanOrEqualToDuration: ( + min: Duration.DurationInput, + options?: FilterAnnotations | undefined +) => (self: Schema) => Schema +``` + +Added in v1.0.0 + +## lessThanDuration + +**Signature** + +```ts +export declare const lessThanDuration: ( + max: Duration.DurationInput, + options?: FilterAnnotations | undefined +) => (self: Schema) => Schema +``` + +Added in v1.0.0 + +## lessThanOrEqualToDuration + +**Signature** + +```ts +export declare const lessThanOrEqualToDuration: ( + max: Duration.DurationInput, + options?: FilterAnnotations | undefined +) => (self: Schema) => Schema +``` + +Added in v1.0.0 + # Duration transformations +## clampDuration + +Clamps a `Duration` between a minimum and a maximum value. + +**Signature** + +```ts +export declare const clampDuration: ( + minimum: Duration.DurationInput, + maximum: Duration.DurationInput +) => (self: Schema) => Schema +``` + +Added in v1.0.0 + ## durationFromHrTime A combinator that transforms a `[number, number]` tuple into a `Duration`. @@ -736,6 +861,32 @@ export declare const durationFromHrTime: (self: Schema) => Schema +``` + +Added in v1.0.0 + +## durationFromNanos + +A combinator that transforms a `bigint` into a `Duration`. +Treats the value as the number of nanoseconds. + +**Signature** + +```ts +export declare const durationFromNanos: (self: Schema) => Schema +``` + +Added in v1.0.0 + # Either transformations ## EitherFrom (type alias) @@ -3249,6 +3400,16 @@ export type BetweenBigintTypeId = typeof BetweenBigintTypeId Added in v1.0.0 +## BetweenDurationTypeId + +**Signature** + +```ts +export declare const BetweenDurationTypeId: typeof BetweenDurationTypeId +``` + +Added in v1.0.0 + ## BetweenTypeId **Signature** @@ -3329,6 +3490,16 @@ export type GreaterThanBigintTypeId = typeof GreaterThanBigintTypeId Added in v1.0.0 +## GreaterThanDurationTypeId + +**Signature** + +```ts +export declare const GreaterThanDurationTypeId: typeof GreaterThanDurationTypeId +``` + +Added in v1.0.0 + ## GreaterThanOrEqualToBigDecimalTypeId **Signature** @@ -3359,6 +3530,16 @@ export type GreaterThanOrEqualToBigintTypeId = typeof GreaterThanOrEqualToBigint Added in v1.0.0 +## GreaterThanOrEqualToDurationTypeId + +**Signature** + +```ts +export declare const GreaterThanOrEqualToDurationTypeId: typeof GreaterThanOrEqualToDurationTypeId +``` + +Added in v1.0.0 + ## GreaterThanOrEqualToTypeId **Signature** @@ -3519,6 +3700,16 @@ export type LessThanBigintTypeId = typeof LessThanBigintTypeId Added in v1.0.0 +## LessThanDurationTypeId + +**Signature** + +```ts +export declare const LessThanDurationTypeId: typeof LessThanDurationTypeId +``` + +Added in v1.0.0 + ## LessThanOrEqualToBigDecimalTypeId **Signature** @@ -3549,6 +3740,16 @@ export type LessThanOrEqualToBigintTypeId = typeof LessThanOrEqualToBigintTypeId Added in v1.0.0 +## LessThanOrEqualToDurationTypeId + +**Signature** + +```ts +export declare const LessThanOrEqualToDurationTypeId: typeof LessThanOrEqualToDurationTypeId +``` + +Added in v1.0.0 + ## LessThanOrEqualToTypeId **Signature** diff --git a/dtslint/Schema.ts b/dtslint/Schema.ts index 23b579b8b..de9c8a11f 100644 --- a/dtslint/Schema.ts +++ b/dtslint/Schema.ts @@ -772,3 +772,25 @@ S.BigDecimalFromNumber // $ExpectType Schema S.bigDecimalFromString(S.string) + +// --------------------------------------------- +// Duration +// --------------------------------------------- + +// $ExpectType Schema +S.Duration + +// $ExpectType Schema +S.DurationFromSelf + +// $ExpectType Schema +S.durationFromMillis(S.number) + +// $ExpectType Schema +S.DurationFromMillis + +// $ExpectType Schema +S.durationFromNanos(S.bigintFromSelf) + +// $ExpectType Schema +S.DurationFromNanos diff --git a/src/Schema.ts b/src/Schema.ts index 99fd6b71b..06aae0d5c 100644 --- a/src/Schema.ts +++ b/src/Schema.ts @@ -2961,13 +2961,10 @@ export const DurationFromSelf: Schema = declare( : ParseResult.succeed(u), { [AST.IdentifierAnnotationId]: "Duration", - [hooks.PrettyHookId]: (): Pretty => - Duration.match({ - onMillis: (_) => `Duration.millis(${_})`, - onNanos: (_) => `Duration.nanos(${_})` - }), + [hooks.PrettyHookId]: (): Pretty => (duration) => String(duration), [hooks.ArbitraryHookId]: (): Arbitrary => (fc) => fc.oneof( + fc.constant(Duration.infinity), fc.bigUint().map((_) => Duration.nanos(_)), fc.bigUint().map((_) => Duration.micros(_)), fc.maxSafeNat().map((_) => Duration.millis(_)), @@ -3002,15 +2999,85 @@ export const durationFromHrTime = ( + self: Schema +): Schema => + transformOrFail( + self, + DurationFromSelf, + (nanos) => ParseResult.succeed(Duration.nanos(nanos)), + (duration, _, ast) => + Duration.toNanos(duration).pipe(Option.match({ + onNone: () => ParseResult.fail(ParseResult.type(ast, duration)), + onSome: (val) => ParseResult.succeed(val) + })), + { strict: false } + ) + +/** + * A schema that transforms a `bigint` tuple into a `Duration`. + * Treats the value as the number of nanoseconds. + * + * @category Duration constructors + * @since 1.0.0 + */ +export const DurationFromNanos: Schema< + bigint, + Duration.Duration +> = durationFromNanos(bigintFromSelf) + +/** + * A combinator that transforms a `number` into a `Duration`. + * Treats the value as the number of milliseconds. + * + * @category Duration transformations + * @since 1.0.0 + */ +export const durationFromMillis = ( + self: Schema +): Schema => + transform( + self, + DurationFromSelf, + (ms) => Duration.millis(ms), + (n) => Duration.toMillis(n), + { strict: false } + ) + +/** + * A schema that transforms a `number` tuple into a `Duration`. + * Treats the value as the number of milliseconds. + * + * @category Duration constructors + * @since 1.0.0 + */ +export const DurationFromMillis: Schema< + number, + Duration.Duration +> = durationFromMillis(number) + const hrTime: Schema = tuple( - NonNegative.pipe(annotations({ - [AST.TitleAnnotationId]: "seconds", - [AST.DescriptionAnnotationId]: "seconds" - })), - NonNegative.pipe(annotations({ - [AST.TitleAnnotationId]: "nanos", - [AST.DescriptionAnnotationId]: "nanos" - })) + NonNegative.pipe( + annotations({ + [AST.TitleAnnotationId]: "seconds", + [AST.DescriptionAnnotationId]: "seconds" + }), + finite() + ), + NonNegative.pipe( + annotations({ + [AST.TitleAnnotationId]: "nanos", + [AST.DescriptionAnnotationId]: "nanos" + }), + finite() + ) ).pipe(annotations({ [AST.TitleAnnotationId]: "a high resolution time tuple", [AST.DescriptionAnnotationId]: "a high resolution time tuple" @@ -3029,6 +3096,147 @@ export { _Duration as Duration } +/** + * Clamps a `Duration` between a minimum and a maximum value. + * + * @category Duration transformations + * @since 1.0.0 + */ +export const clampDuration = + (minimum: Duration.DurationInput, maximum: Duration.DurationInput) => + (self: Schema): Schema => + transform( + self, + self.pipe(to, betweenDuration(minimum, maximum)), + (self) => Duration.clamp(self, { minimum, maximum }), + identity, + { strict: false } + ) + +// --------------------------------------------- +// Duration filters +// --------------------------------------------- + +/** + * @category type id + * @since 1.0.0 + */ +export const LessThanDurationTypeId = Symbol.for("@effect/schema/TypeId/LessThanDuration") + +/** + * @category Duration filters + * @since 1.0.0 + */ +export const lessThanDuration = ( + max: Duration.DurationInput, + options?: FilterAnnotations +) => +(self: Schema): Schema => + self.pipe( + filter((a): a is A => Duration.lessThan(a, max), { + typeId: { id: LessThanDurationTypeId, params: { max } }, + description: `a Duration less than ${Duration.decode(max)}`, + ...options + }) + ) + +/** + * @category type id + * @since 1.0.0 + */ +export const LessThanOrEqualToDurationTypeId = Symbol.for( + "@effect/schema/TypeId/LessThanOrEqualToDuration" +) + +/** + * @category Duration filters + * @since 1.0.0 + */ +export const lessThanOrEqualToDuration = ( + max: Duration.DurationInput, + options?: FilterAnnotations +) => +(self: Schema): Schema => + self.pipe( + filter((a): a is A => Duration.lessThanOrEqualTo(a, max), { + typeId: { id: LessThanDurationTypeId, params: { max } }, + description: `a Duration less than or equal to ${Duration.decode(max)}`, + ...options + }) + ) + +/** + * @category type id + * @since 1.0.0 + */ +export const GreaterThanDurationTypeId = Symbol.for("@effect/schema/TypeId/GreaterThanDuration") + +/** + * @category Duration filters + * @since 1.0.0 + */ +export const greaterThanDuration = ( + min: Duration.DurationInput, + options?: FilterAnnotations +) => +(self: Schema): Schema => + self.pipe( + filter((a): a is A => Duration.greaterThan(a, min), { + typeId: { id: GreaterThanDurationTypeId, params: { min } }, + description: `a Duration greater than ${Duration.decode(min)}`, + ...options + }) + ) + +/** + * @category type id + * @since 1.0.0 + */ +export const GreaterThanOrEqualToDurationTypeId = Symbol.for( + "@effect/schema/TypeId/GreaterThanOrEqualToDuration" +) + +/** + * @category Duration filters + * @since 1.0.0 + */ +export const greaterThanOrEqualToDuration = ( + min: Duration.DurationInput, + options?: FilterAnnotations +) => +(self: Schema): Schema => + self.pipe( + filter((a): a is A => Duration.greaterThanOrEqualTo(a, min), { + typeId: { id: GreaterThanOrEqualToDurationTypeId, params: { min } }, + description: `a Duration greater than or equal to ${Duration.decode(min)}`, + ...options + }) + ) + +/** + * @category type id + * @since 1.0.0 + */ +export const BetweenDurationTypeId = Symbol.for("@effect/schema/TypeId/BetweenDuration") + +/** + * @category Duration filters + * @since 1.0.0 + */ +export const betweenDuration = ( + minimum: Duration.DurationInput, + maximum: Duration.DurationInput, + options?: FilterAnnotations +) => +(self: Schema): Schema => + self.pipe( + filter((a): a is A => Duration.between(a, { minimum, maximum }), { + typeId: { id: BetweenDurationTypeId, params: { maximum, minimum } }, + description: `a Duration between ${Duration.decode(minimum)} and ${Duration.decode(maximum)}`, + ...options + }) + ) + // --------------------------------------------- // Uint8Array constructors // --------------------------------------------- diff --git a/test/Duration/DurationFromBigint.test.ts b/test/Duration/DurationFromBigint.test.ts new file mode 100644 index 000000000..f9934f03b --- /dev/null +++ b/test/Duration/DurationFromBigint.test.ts @@ -0,0 +1,22 @@ +import * as S from "@effect/schema/Schema" +import * as Util from "@effect/schema/test/util" +import { Duration } from "effect" +import { describe, it } from "vitest" + +describe("Schema/DurationFromBigint", () => { + const schema = S.DurationFromNanos + + it("property tests", () => { + Util.roundtrip(schema) + }) + + it("decoding", async () => { + await Util.expectParseSuccess(schema, 0n, Duration.nanos(0n)) + await Util.expectParseSuccess(schema, 1000n, Duration.nanos(1000n)) + }) + + it("encoding", async () => { + await Util.expectEncodeSuccess(schema, Duration.millis(5), 5000000n) + await Util.expectEncodeSuccess(schema, Duration.nanos(5000n), 5000n) + }) +}) diff --git a/test/Duration/DurationFromNumber.test.ts b/test/Duration/DurationFromNumber.test.ts new file mode 100644 index 000000000..803620d25 --- /dev/null +++ b/test/Duration/DurationFromNumber.test.ts @@ -0,0 +1,24 @@ +import * as S from "@effect/schema/Schema" +import * as Util from "@effect/schema/test/util" +import { Duration } from "effect" +import { describe, it } from "vitest" + +describe("Schema/DurationFromNumber", () => { + const schema = S.DurationFromMillis + + it("property tests", () => { + Util.roundtrip(schema) + }) + + it("decoding", async () => { + await Util.expectParseSuccess(schema, 0, Duration.millis(0)) + await Util.expectParseSuccess(schema, 1000, Duration.seconds(1)) + await Util.expectParseSuccess(schema, 60 * 1000, Duration.minutes(1)) + }) + + it("encoding", async () => { + await Util.expectEncodeSuccess(schema, Duration.seconds(5), 5000) + await Util.expectEncodeSuccess(schema, Duration.millis(5000), 5000) + await Util.expectEncodeSuccess(schema, Duration.nanos(5000n), 0.005) + }) +}) diff --git a/test/Duration/DurationFromSelf.test.ts b/test/Duration/DurationFromSelf.test.ts index 7bbd51d34..bc54317a2 100644 --- a/test/Duration/DurationFromSelf.test.ts +++ b/test/Duration/DurationFromSelf.test.ts @@ -1,7 +1,8 @@ +import * as Pretty from "@effect/schema/Pretty" import * as S from "@effect/schema/Schema" import * as Util from "@effect/schema/test/util" import { Duration } from "effect" -import { describe, it } from "vitest" +import { describe, expect, it } from "vitest" describe("Schema/DurationFromSelf", () => { const schema = S.DurationFromSelf @@ -20,4 +21,12 @@ describe("Schema/DurationFromSelf", () => { it("encoding", async () => { await Util.expectEncodeSuccess(schema, Duration.seconds(5), Duration.seconds(5)) }) + + it("pretty", () => { + const pretty = Pretty.to(schema) + + expect(pretty(Duration.millis(500))).toEqual("Duration(500ms)") + expect(pretty(Duration.seconds(30))).toEqual("Duration(30s)") + expect(pretty(Duration.minutes(5.25))).toEqual("Duration(5m 15s)") + }) }) diff --git a/test/Duration/betweenDuration.test.ts b/test/Duration/betweenDuration.test.ts new file mode 100644 index 000000000..23164f775 --- /dev/null +++ b/test/Duration/betweenDuration.test.ts @@ -0,0 +1,36 @@ +import * as S from "@effect/schema/Schema" +import * as Util from "@effect/schema/test/util" +import { Duration } from "effect" +import { describe, it } from "vitest" + +describe("Schema/betweenDuration", () => { + const schema = S.DurationFromSelf.pipe(S.betweenDuration("5 seconds", "10 seconds")) + + it("decoding", async () => { + await Util.expectParseFailure( + schema, + Duration.decode("4 seconds"), + `Expected a Duration between Duration(5s) and Duration(10s), actual Duration(4s)` + ) + + await Util.expectParseSuccess( + schema, + Duration.decode("7 seconds"), + Duration.decode("7 seconds") + ) + + await Util.expectParseFailure( + schema, + Duration.decode("11 seconds"), + `Expected a Duration between Duration(5s) and Duration(10s), actual Duration(11s)` + ) + }) + + it("encoding", async () => { + await Util.expectEncodeSuccess( + schema, + Duration.decode("7 seconds"), + Duration.decode("7 seconds") + ) + }) +}) diff --git a/test/Duration/clampDuration.test.ts b/test/Duration/clampDuration.test.ts new file mode 100644 index 000000000..6cfcb01c5 --- /dev/null +++ b/test/Duration/clampDuration.test.ts @@ -0,0 +1,28 @@ +import * as S from "@effect/schema/Schema" +import * as Util from "@effect/schema/test/util" +import { Duration } from "effect" +import { describe, it } from "vitest" + +describe("Schema/clampDuration", () => { + it("decoding", async () => { + const schema = S.DurationFromSelf.pipe(S.clampDuration("5 seconds", "10 seconds")) + + await Util.expectParseSuccess( + schema, + Duration.decode("1 seconds"), + Duration.decode("5 seconds") + ) + + await Util.expectParseSuccess( + schema, + Duration.decode("6 seconds"), + Duration.decode("6 seconds") + ) + + await Util.expectParseSuccess( + schema, + Duration.decode("11 seconds"), + Duration.decode("10 seconds") + ) + }) +}) diff --git a/test/Duration/greaterThanDuration.test.ts b/test/Duration/greaterThanDuration.test.ts new file mode 100644 index 000000000..7a267ff7d --- /dev/null +++ b/test/Duration/greaterThanDuration.test.ts @@ -0,0 +1,36 @@ +import * as S from "@effect/schema/Schema" +import * as Util from "@effect/schema/test/util" +import { Duration } from "effect" +import { describe, it } from "vitest" + +describe("Schema/greaterThanDuration", () => { + const schema = S.DurationFromSelf.pipe(S.greaterThanDuration("5 seconds")) + + it("decoding", async () => { + await Util.expectParseSuccess( + schema, + Duration.decode("6 seconds"), + Duration.decode("6 seconds") + ) + + await Util.expectParseFailure( + schema, + Duration.decode("5 seconds"), + `Expected a Duration greater than Duration(5s), actual Duration(5s)` + ) + + await Util.expectParseFailure( + schema, + Duration.decode("4 seconds"), + `Expected a Duration greater than Duration(5s), actual Duration(4s)` + ) + }) + + it("encoding", async () => { + await Util.expectEncodeSuccess( + schema, + Duration.decode("6 seconds"), + Duration.decode("6 seconds") + ) + }) +}) diff --git a/test/Duration/greaterThanOrEqualToDuration.test.ts b/test/Duration/greaterThanOrEqualToDuration.test.ts new file mode 100644 index 000000000..034721d74 --- /dev/null +++ b/test/Duration/greaterThanOrEqualToDuration.test.ts @@ -0,0 +1,36 @@ +import * as S from "@effect/schema/Schema" +import * as Util from "@effect/schema/test/util" +import { Duration } from "effect" +import { describe, it } from "vitest" + +describe("Schema/greaterThanOrEqualToDuration", () => { + const schema = S.DurationFromSelf.pipe(S.greaterThanOrEqualToDuration("5 seconds")) + + it("decoding", async () => { + await Util.expectParseSuccess( + schema, + Duration.decode("6 seconds"), + Duration.decode("6 seconds") + ) + + await Util.expectParseSuccess( + schema, + Duration.decode("5 seconds"), + Duration.decode("5 seconds") + ) + + await Util.expectParseFailure( + schema, + Duration.decode("4 seconds"), + `Expected a Duration greater than or equal to Duration(5s), actual Duration(4s)` + ) + }) + + it("encoding", async () => { + await Util.expectEncodeSuccess( + schema, + Duration.decode("5 seconds"), + Duration.decode("5 seconds") + ) + }) +}) diff --git a/test/Duration/lessThanDuration.test.ts b/test/Duration/lessThanDuration.test.ts new file mode 100644 index 000000000..e50c4e790 --- /dev/null +++ b/test/Duration/lessThanDuration.test.ts @@ -0,0 +1,36 @@ +import * as S from "@effect/schema/Schema" +import * as Util from "@effect/schema/test/util" +import { Duration } from "effect" +import { describe, it } from "vitest" + +describe("Schema/lessThanDuration", () => { + const schema = S.DurationFromSelf.pipe(S.lessThanDuration("5 seconds")) + + it("decoding", async () => { + await Util.expectParseSuccess( + schema, + Duration.decode("4 seconds"), + Duration.decode("4 seconds") + ) + + await Util.expectParseFailure( + schema, + Duration.decode("5 seconds"), + `Expected a Duration less than Duration(5s), actual Duration(5s)` + ) + + await Util.expectParseFailure( + schema, + Duration.decode("6 seconds"), + `Expected a Duration less than Duration(5s), actual Duration(6s)` + ) + }) + + it("encoding", async () => { + await Util.expectEncodeSuccess( + schema, + Duration.decode("4 seconds"), + Duration.decode("4 seconds") + ) + }) +}) diff --git a/test/Duration/lessThanOrEqualToDuration.test.ts b/test/Duration/lessThanOrEqualToDuration.test.ts new file mode 100644 index 000000000..f244f178a --- /dev/null +++ b/test/Duration/lessThanOrEqualToDuration.test.ts @@ -0,0 +1,36 @@ +import * as S from "@effect/schema/Schema" +import * as Util from "@effect/schema/test/util" +import { Duration } from "effect" +import { describe, it } from "vitest" + +describe("Schema/lessThanDuration", () => { + const schema = S.DurationFromSelf.pipe(S.lessThanOrEqualToDuration("5 seconds")) + + it("decoding", async () => { + await Util.expectParseSuccess( + schema, + Duration.decode("4 seconds"), + Duration.decode("4 seconds") + ) + + await Util.expectParseSuccess( + schema, + Duration.decode("5 seconds"), + Duration.decode("5 seconds") + ) + + await Util.expectParseFailure( + schema, + Duration.decode("6 seconds"), + `Expected a Duration less than or equal to Duration(5s), actual Duration(6s)` + ) + }) + + it("encoding", async () => { + await Util.expectEncodeSuccess( + schema, + Duration.decode("5 seconds"), + Duration.decode("5 seconds") + ) + }) +})