1import * as Option from "effect/Option"
2import * as Schema from "effect/Schema"
3import assert from "node:assert/strict"
4import { invalidData, validData } from "./data.ts"
5
6// Extracted from open-circle/schema-benchmarks at
7// 11fab2a741cef95a1374910276023c51218c0683.
8
9const makeSchema = () => {
10 const Image = Schema.Struct({
11 id: Schema.Number,
12 created: Schema.instanceOf(Date),
13 title: Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(100)),
14 type: Schema.Literals(["jpg", "png"]),
15 size: Schema.Number,
16 url: Schema.String.check(Schema.makeFilter((value) => URL.canParse(value)))
17 })
18 const Rating = Schema.Struct({
19 id: Schema.Number,
20 stars: Schema.Number.check(Schema.isGreaterThanOrEqualTo(0), Schema.isLessThanOrEqualTo(5)),
21 title: Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(100)),
22 text: Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(1000)),
23 images: Schema.mutable(Schema.Array(Image))
24 })
25 return Schema.Struct({
26 id: Schema.Number,
27 created: Schema.instanceOf(Date),
28 title: Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(100)),
29 brand: Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(30)),
30 description: Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(500)),
31 price: Schema.Number.check(Schema.isGreaterThanOrEqualTo(1), Schema.isLessThanOrEqualTo(10000)),
32 discount: Schema.NullOr(
33 Schema.Number.check(Schema.isGreaterThanOrEqualTo(1), Schema.isLessThanOrEqualTo(100))
34 ),
35 quantity: Schema.Number.check(Schema.isGreaterThanOrEqualTo(1), Schema.isLessThanOrEqualTo(10)),
36 tags: Schema.mutable(
37 Schema.Array(Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(30)))
38 ),
39 images: Schema.mutable(Schema.Array(Image)),
40 ratings: Schema.mutable(Schema.Array(Rating))
41 })
42}
43
44export const initializationSchema = () => ({
45 run: makeSchema,
46 validate: (schema) => assert.equal(schema.ast._tag, "Objects")
47})
48
49export const initializationDecoder = () => ({
50 run: () => Schema.decodeUnknownOption(makeSchema()),
51 validate: (decode) => assert.equal(typeof decode, "function")
52})
53
54const validationCase = (input, expected) => () => {
55 const run = Schema.is(makeSchema())
56 return {
57 run: () => run(input),
58 validate: (result) => assert.equal(result, expected)
59 }
60}
61
62export const validationValid = validationCase(validData, true)
63export const validationInvalid = validationCase(invalidData, false)
64
65const parsingCase = (input, errors, success) => () => {
66 const run = Schema.decodeUnknownOption(makeSchema())
67 return {
68 run: () => run(input, { errors }),
69 validate: (result) => {
70 assert.equal(Option.isSome(result), success)
71 if (success && Option.isSome(result)) assert.deepEqual(result.value, validData)
72 }
73 }
74}
75
76export const parsingAllValid = parsingCase(validData, "all", true)
77export const parsingAllInvalid = parsingCase(invalidData, "all", false)
78export const parsingFirstValid = parsingCase(validData, "first", true)
79export const parsingFirstInvalid = parsingCase(invalidData, "first", false)
80
81const standardCase = (input, errors, success) => () => {
82 const schema = Schema.toStandardSchemaV1(makeSchema(), { parseOptions: { errors } })
83 return {
84 run: () => schema["~standard"].validate(input),
85 validate: (result) => {
86 assert.equal(typeof result?.then, "undefined")
87 if (success) {
88 assert.equal(result.issues, undefined)
89 assert.deepEqual(result.value, validData)
90 } else {
91 assert.ok(result.issues)
92 assert.ok(result.issues.length > 0)
93 }
94 }
95 }
96}
97
98export const standardAllValid = standardCase(validData, "all", true)
99export const standardAllInvalid = standardCase(invalidData, "all", false)
100export const standardFirstValid = standardCase(validData, "first", true)
101export const standardFirstInvalid = standardCase(invalidData, "first", false)
102
103const bigint = BigInt("1234567890123456789")
104const bigintString = bigint.toString()
105
106export const codecTypedEncode = () => {
107 const run = Schema.encodeSync(Schema.BigIntFromString)
108 return {
109 run: () => run(bigint),
110 validate: (result) => assert.equal(result, bigintString)
111 }
112}
113
114export const codecTypedDecode = () => {
115 const run = Schema.decodeSync(Schema.BigIntFromString)
116 return {
117 run: () => run(bigintString),
118 validate: (result) => assert.equal(result, bigint)
119 }
120}
121
122export const codecUnknownEncode = () => {
123 const run = Schema.encodeUnknownSync(Schema.BigIntFromString)
124 return {
125 run: () => run(bigint),
126 validate: (result) => assert.equal(result, bigintString)
127 }
128}
129
130export const codecUnknownDecode = () => {
131 const run = Schema.decodeUnknownSync(Schema.BigIntFromString)
132 return {
133 run: () => run(bigintString),
134 validate: (result) => assert.equal(result, bigint)
135 }
136}