/
dimamir
/
undb
Обзор
Документация
Войти
/
dimamir
/
undb
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
develop
packages/domain/src/specification.ts
136 строк
3 KB
nichenqin
chore: prettier
14 май 2024, 04:57
14 май 2024, 04:57
5c0eb73
Код
Авторство
О чём код?
import type { Option, Result } from "oxide.ts" import { None, Ok, Some } from "oxide.ts" export interface ISpecVisitor { and(left: ISpecification, right: ISpecification): this or(left: ISpecification, right: ISpecification): this not(spec: ISpecification): this clone(): this } export interface ISpecification<T = any, V extends ISpecVisitor = ISpecVisitor> { isSatisfiedBy(t: T): boolean mutate(t: T): Result<T, string> accept(v: V): Result<void, string> } export abstract class CompositeSpecification<T = any, V extends ISpecVisitor = ISpecVisitor> implements ISpecification<T, V> { abstract isSatisfiedBy(t: T): boolean abstract mutate(t: T): Result<T, string> abstract accept(v: V): Result<void, string> public and(s: ISpecification<T, V>): CompositeSpecification<T, V> { return new And(this, s) } public or(s: ISpecification<T, V>): CompositeSpecification<T, V> { return new Or(this, s) } public not(): Not<T, V> { return new Not(this) } } class And<T, V extends ISpecVisitor> extends CompositeSpecification<T, V> { constructor( private readonly left: ISpecification<T, V>, private readonly right: ISpecification<T, V>, ) { super() } isSatisfiedBy(t: T): boolean { return this.left.isSatisfiedBy(t) && this.right.isSatisfiedBy(t) } mutate(t: T): Result<T, string> { return this.left.mutate(t).and(this.right.mutate(t)) } accept(v: V): Result<void, string> { v.and(this.left, this.right) return Ok(undefined) } } class Or<T, V extends ISpecVisitor> extends CompositeSpecification<T, V> { constructor( private readonly left: ISpecification<T, V>, private readonly right: ISpecification<T, V>, ) { super() } isSatisfiedBy(t: T): boolean { return this.left.isSatisfiedBy(t) || this.right.isSatisfiedBy(t) } mutate(t: T): Result<T, string> { return this.left.mutate(t).orElse(() => this.right.mutate(t)) } accept(v: V): Result<void, string> { v.or(this.left, this.right) return Ok(undefined) } } export class Not<T, V extends ISpecVisitor> extends CompositeSpecification<T, V> { constructor(public readonly spec: ISpecification<T, V>) { super() } isSatisfiedBy(t: T): boolean { return !this.spec.isSatisfiedBy(t) } mutate(): Result<T, string> { throw new Error("[Not.mutate] Method not implemented.") } accept(v: V): Result<void, string> { v.not(this.spec) return Ok(undefined) } } export const and = <T, V extends ISpecVisitor>( ...specs: CompositeSpecification<T, V>[] ): Option<CompositeSpecification<T, V>> => { if (!specs.length) return None let s = specs[0] for (const spec of specs.slice(1)) { s = s.and(spec) } return Some(s) } export const andOptions = <T, V extends ISpecVisitor>( ...specs: Option<CompositeSpecification<T, V>>[] ): Option<CompositeSpecification<T, V>> => { return and(...specs.filter((spec) => spec.isSome()).map((spec) => spec.unwrap())) } export const or = <T, V extends ISpecVisitor>( ...specs: CompositeSpecification<T, V>[] ): Option<CompositeSpecification<T, V>> => { if (!specs.length) return None let s = specs[0] for (const spec of specs.slice(1)) { s = s.or(spec) } return Some(s) } export const orOptions = <T, V extends ISpecVisitor>( ...specs: Option<CompositeSpecification<T, V>>[] ): Option<CompositeSpecification<T, V>> => { return or(...specs.filter((spec) => spec.isSome()).map((spec) => spec.unwrap())) }