initial commit
This commit is contained in:
148
benchmarks/scenarios/validation-pipeline.bench.ts
Normal file
148
benchmarks/scenarios/validation-pipeline.bench.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
import { bench, describe } from 'vitest';
|
||||
import { STANDARD } from '../helpers/bench-options.js';
|
||||
import {
|
||||
ok,
|
||||
err,
|
||||
ntOk,
|
||||
ntErr,
|
||||
TsOk,
|
||||
TsErr,
|
||||
OxOk,
|
||||
OxErr,
|
||||
E,
|
||||
pipe,
|
||||
TmResult,
|
||||
} from '../helpers/imports.js';
|
||||
|
||||
interface User {
|
||||
name: string;
|
||||
email: string;
|
||||
age: number;
|
||||
}
|
||||
|
||||
const validUser: User = { name: 'Alice', email: 'alice@example.com', age: 30 };
|
||||
const invalidUser: User = { name: '', email: 'alice@example.com', age: 30 };
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 5-check validation — all pass
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Scenario: 5-check validation pipeline — all pass', () => {
|
||||
bench('native-monad', () => {
|
||||
ok<User, string>(validUser)
|
||||
.flatMap(u => (u.name ? ok(u) : err('name required')))
|
||||
.flatMap(u => (u.email.includes('@') ? ok(u) : err('invalid email')))
|
||||
.flatMap(u => (u.age >= 18 ? ok(u) : err('must be 18+')))
|
||||
.flatMap(u => (u.age <= 120 ? ok(u) : err('unrealistic age')))
|
||||
.map(u => ({ ...u, validated: true }));
|
||||
}, STANDARD);
|
||||
|
||||
bench('neverthrow', () => {
|
||||
ntOk<User, string>(validUser)
|
||||
.andThen(u => (u.name ? ntOk(u) : ntErr('name required')))
|
||||
.andThen(u => (u.email.includes('@') ? ntOk(u) : ntErr('invalid email')))
|
||||
.andThen(u => (u.age >= 18 ? ntOk(u) : ntErr('must be 18+')))
|
||||
.andThen(u => (u.age <= 120 ? ntOk(u) : ntErr('unrealistic age')))
|
||||
.map(u => ({ ...u, validated: true }));
|
||||
}, STANDARD);
|
||||
|
||||
bench('ts-results-es', () => {
|
||||
TsOk<User, string>(validUser)
|
||||
.andThen(u => (u.name ? TsOk(u) : TsErr('name required')))
|
||||
.andThen(u => (u.email.includes('@') ? TsOk(u) : TsErr('invalid email')))
|
||||
.andThen(u => (u.age >= 18 ? TsOk(u) : TsErr('must be 18+')))
|
||||
.andThen(u => (u.age <= 120 ? TsOk(u) : TsErr('unrealistic age')))
|
||||
.map(u => ({ ...u, validated: true }));
|
||||
}, STANDARD);
|
||||
|
||||
bench('oxide.ts', () => {
|
||||
OxOk<User, string>(validUser)
|
||||
.andThen(u => (u.name ? OxOk(u) : OxErr('name required')))
|
||||
.andThen(u => (u.email.includes('@') ? OxOk(u) : OxErr('invalid email')))
|
||||
.andThen(u => (u.age >= 18 ? OxOk(u) : OxErr('must be 18+')))
|
||||
.andThen(u => (u.age <= 120 ? OxOk(u) : OxErr('unrealistic age')))
|
||||
.map(u => ({ ...u, validated: true }));
|
||||
}, STANDARD);
|
||||
|
||||
bench('fp-ts', () => {
|
||||
pipe(
|
||||
E.right<string, User>(validUser),
|
||||
E.flatMap(u => (u.name ? E.right(u) : E.left('name required'))),
|
||||
E.flatMap(u => (u.email.includes('@') ? E.right(u) : E.left('invalid email'))),
|
||||
E.flatMap(u => (u.age >= 18 ? E.right(u) : E.left('must be 18+'))),
|
||||
E.flatMap(u => (u.age <= 120 ? E.right(u) : E.left('unrealistic age'))),
|
||||
E.map(u => ({ ...u, validated: true })),
|
||||
);
|
||||
}, STANDARD);
|
||||
|
||||
bench('true-myth', () => {
|
||||
TmResult.ok<User, string>(validUser)
|
||||
.andThen(u => (u.name ? TmResult.ok(u) : TmResult.err('name required')))
|
||||
.andThen(u => (u.email.includes('@') ? TmResult.ok(u) : TmResult.err('invalid email')))
|
||||
.andThen(u => (u.age >= 18 ? TmResult.ok(u) : TmResult.err('must be 18+')))
|
||||
.andThen(u => (u.age <= 120 ? TmResult.ok(u) : TmResult.err('unrealistic age')))
|
||||
.map(u => ({ ...u, validated: true }));
|
||||
}, STANDARD);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 5-check validation — fails at step 1 (early exit)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('Scenario: 5-check validation pipeline — fails at step 1', () => {
|
||||
bench('native-monad', () => {
|
||||
ok<User, string>(invalidUser)
|
||||
.flatMap(u => (u.name ? ok(u) : err('name required')))
|
||||
.flatMap(u => (u.email.includes('@') ? ok(u) : err('invalid email')))
|
||||
.flatMap(u => (u.age >= 18 ? ok(u) : err('must be 18+')))
|
||||
.flatMap(u => (u.age <= 120 ? ok(u) : err('unrealistic age')))
|
||||
.map(u => ({ ...u, validated: true }));
|
||||
}, STANDARD);
|
||||
|
||||
bench('neverthrow', () => {
|
||||
ntOk<User, string>(invalidUser)
|
||||
.andThen(u => (u.name ? ntOk(u) : ntErr('name required')))
|
||||
.andThen(u => (u.email.includes('@') ? ntOk(u) : ntErr('invalid email')))
|
||||
.andThen(u => (u.age >= 18 ? ntOk(u) : ntErr('must be 18+')))
|
||||
.andThen(u => (u.age <= 120 ? ntOk(u) : ntErr('unrealistic age')))
|
||||
.map(u => ({ ...u, validated: true }));
|
||||
}, STANDARD);
|
||||
|
||||
bench('ts-results-es', () => {
|
||||
TsOk<User, string>(invalidUser)
|
||||
.andThen(u => (u.name ? TsOk(u) : TsErr('name required')))
|
||||
.andThen(u => (u.email.includes('@') ? TsOk(u) : TsErr('invalid email')))
|
||||
.andThen(u => (u.age >= 18 ? TsOk(u) : TsErr('must be 18+')))
|
||||
.andThen(u => (u.age <= 120 ? TsOk(u) : TsErr('unrealistic age')))
|
||||
.map(u => ({ ...u, validated: true }));
|
||||
}, STANDARD);
|
||||
|
||||
bench('oxide.ts', () => {
|
||||
OxOk<User, string>(invalidUser)
|
||||
.andThen(u => (u.name ? OxOk(u) : OxErr('name required')))
|
||||
.andThen(u => (u.email.includes('@') ? OxOk(u) : OxErr('invalid email')))
|
||||
.andThen(u => (u.age >= 18 ? OxOk(u) : OxErr('must be 18+')))
|
||||
.andThen(u => (u.age <= 120 ? OxOk(u) : OxErr('unrealistic age')))
|
||||
.map(u => ({ ...u, validated: true }));
|
||||
}, STANDARD);
|
||||
|
||||
bench('fp-ts', () => {
|
||||
pipe(
|
||||
E.right<string, User>(invalidUser),
|
||||
E.flatMap(u => (u.name ? E.right(u) : E.left('name required'))),
|
||||
E.flatMap(u => (u.email.includes('@') ? E.right(u) : E.left('invalid email'))),
|
||||
E.flatMap(u => (u.age >= 18 ? E.right(u) : E.left('must be 18+'))),
|
||||
E.flatMap(u => (u.age <= 120 ? E.right(u) : E.left('unrealistic age'))),
|
||||
E.map(u => ({ ...u, validated: true })),
|
||||
);
|
||||
}, STANDARD);
|
||||
|
||||
bench('true-myth', () => {
|
||||
TmResult.ok<User, string>(invalidUser)
|
||||
.andThen(u => (u.name ? TmResult.ok(u) : TmResult.err('name required')))
|
||||
.andThen(u => (u.email.includes('@') ? TmResult.ok(u) : TmResult.err('invalid email')))
|
||||
.andThen(u => (u.age >= 18 ? TmResult.ok(u) : TmResult.err('must be 18+')))
|
||||
.andThen(u => (u.age <= 120 ? TmResult.ok(u) : TmResult.err('unrealistic age')))
|
||||
.map(u => ({ ...u, validated: true }));
|
||||
}, STANDARD);
|
||||
});
|
||||
Reference in New Issue
Block a user