add async equality comparer and broaden to comparison or comparer
This commit is contained in:
173
src/equality-comparer/async.ts
Normal file
173
src/equality-comparer/async.ts
Normal file
@@ -0,0 +1,173 @@
|
||||
import { MaybeAsyncConverter } from "../types.js";
|
||||
import { Nullable } from "../utils.js";
|
||||
import { AsyncEqualityComparer, AsyncEqualityComparison, EqualityComparer, MaybeAsyncEqualityComparison, MaybeAsyncEqualityComparisonOrComparer } from "./types.js";
|
||||
|
||||
export function isAsyncEqualityComparer<T>(obj: any): obj is AsyncEqualityComparer<T> {
|
||||
return obj instanceof BaseAsyncEqualityComparer;
|
||||
}
|
||||
|
||||
export function asAsyncEqualityComparer<T>(equalityComparer: MaybeAsyncEqualityComparisonOrComparer<T>): AsyncEqualityComparer<T> {
|
||||
return typeof equalityComparer === "function" ? createAsyncEqualityComparer(equalityComparer) : isAsyncEqualityComparer<T>(equalityComparer) ? equalityComparer : fromSyncEqualityComparer(equalityComparer);
|
||||
}
|
||||
|
||||
export function fromSyncEqualityComparer<T>(equalityComparer: EqualityComparer<T>): AsyncEqualityComparer<T> {
|
||||
return new WrappedAsyncEqualityComparer(equalityComparer);
|
||||
}
|
||||
|
||||
export function createAsyncEqualityComparer<T = any>(equalityComparison: MaybeAsyncEqualityComparison<T>): AsyncEqualityComparer<T> {
|
||||
return new SimpleAsyncEqualityComparer(equalityComparison);
|
||||
}
|
||||
|
||||
export function createAsyncEqualityComparerUsing<T = any, U = any>(projection: MaybeAsyncConverter<T, U>, equalityComparison?: MaybeAsyncEqualityComparisonOrComparer<U>): AsyncEqualityComparer<T> {
|
||||
return new MappedAsyncEqualityComparer(projection, equalityComparison);
|
||||
}
|
||||
|
||||
export function combineNullableAsyncEqualityComparers<T>(equalityComparers: Nullable<MaybeAsyncEqualityComparisonOrComparer<T>>[]) {
|
||||
let result = defaultAsyncEqualityComparer;
|
||||
|
||||
for (const equalityComparer of equalityComparers) {
|
||||
if (!equalityComparer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result = result.then(asAsyncEqualityComparer(equalityComparer));
|
||||
}
|
||||
|
||||
return result === defaultAsyncEqualityComparer ? undefined : result;
|
||||
}
|
||||
|
||||
export abstract class BaseAsyncEqualityComparer<T> implements AsyncEqualityComparer<T> {
|
||||
#cachedBoundEqualityComparison: AsyncEqualityComparison<T> | undefined;
|
||||
|
||||
public abstract equals(a: T, b: T): Promise<boolean>;
|
||||
|
||||
public equalityComparison(): AsyncEqualityComparison<T> {
|
||||
return this.#cachedBoundEqualityComparison ??= this.equals.bind(this);
|
||||
}
|
||||
|
||||
public opposite(): AsyncEqualityComparer<T> {
|
||||
return new OppositeAsyncEqualityComparer(this);
|
||||
}
|
||||
|
||||
public then(equalityComparer: AsyncEqualityComparer<T>): AsyncEqualityComparer<T> {
|
||||
return new ThenAsyncEqualityComparer(this, equalityComparer);
|
||||
}
|
||||
|
||||
public thenEquals(equalityComparison: MaybeAsyncEqualityComparison<T>): AsyncEqualityComparer<T> {
|
||||
return this.then(createAsyncEqualityComparer(equalityComparison));
|
||||
}
|
||||
|
||||
public thenEqualsUsing<U>(projection: MaybeAsyncConverter<T, U>, equalityComparison?: MaybeAsyncEqualityComparisonOrComparer<U>): AsyncEqualityComparer<T> {
|
||||
return this.then(createAsyncEqualityComparerUsing(projection, equalityComparison));
|
||||
}
|
||||
}
|
||||
|
||||
class WrappedAsyncEqualityComparer<T> extends BaseAsyncEqualityComparer<T> {
|
||||
readonly #base: EqualityComparer<T>;
|
||||
|
||||
constructor(base: EqualityComparer<T>) {
|
||||
super();
|
||||
|
||||
this.#base = base;
|
||||
}
|
||||
|
||||
public override async equals(a: T, b: T) {
|
||||
return this.#base.equals(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
class SimpleAsyncEqualityComparer<T> extends BaseAsyncEqualityComparer<T> {
|
||||
readonly #equalityComparison: MaybeAsyncEqualityComparison<T>;
|
||||
|
||||
public constructor(equalityComparison: MaybeAsyncEqualityComparison<T>) {
|
||||
super();
|
||||
|
||||
this.#equalityComparison = equalityComparison;
|
||||
}
|
||||
|
||||
public override async equals(a: T, b: T): Promise<boolean> {
|
||||
return await this.#equalityComparison(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
class MappedAsyncEqualityComparer<T, U> extends BaseAsyncEqualityComparer<T> {
|
||||
readonly #projection: MaybeAsyncConverter<T, U>;
|
||||
readonly #equalityComparison: AsyncEqualityComparer<U>;
|
||||
|
||||
public constructor(projection: MaybeAsyncConverter<T, U>, equalityComparison?: MaybeAsyncEqualityComparisonOrComparer<U>) {
|
||||
super();
|
||||
|
||||
this.#projection = projection;
|
||||
this.#equalityComparison = equalityComparison ? asAsyncEqualityComparer(equalityComparison) : defaultAsyncEqualityComparer;
|
||||
}
|
||||
|
||||
public override async equals(a: T, b: T): Promise<boolean> {
|
||||
return await this.#equalityComparison.equals(await this.#projection(a), await this.#projection(b));
|
||||
}
|
||||
}
|
||||
|
||||
class OppositeAsyncEqualityComparer<T> extends BaseAsyncEqualityComparer<T> {
|
||||
readonly #base: AsyncEqualityComparer<T>;
|
||||
|
||||
public constructor(base: AsyncEqualityComparer<T>) {
|
||||
super();
|
||||
|
||||
this.#base = base;
|
||||
}
|
||||
|
||||
public override async equals(a: T, b: T): Promise<boolean> {
|
||||
return !(await this.#base.equals(a, b));
|
||||
}
|
||||
|
||||
public override opposite(): AsyncEqualityComparer<T> {
|
||||
return this.#base;
|
||||
}
|
||||
}
|
||||
|
||||
class ThenAsyncEqualityComparer<T> extends BaseAsyncEqualityComparer<T> {
|
||||
readonly #base: AsyncEqualityComparer<T>;
|
||||
readonly #equalityComparer: AsyncEqualityComparer<T>;
|
||||
|
||||
public constructor(base: AsyncEqualityComparer<T>, equalityComparer: AsyncEqualityComparer<T>) {
|
||||
super();
|
||||
|
||||
this.#base = base;
|
||||
this.#equalityComparer = equalityComparer;
|
||||
}
|
||||
|
||||
public override async equals(a: T, b: T) {
|
||||
return await this.#base.equals(a, b) && await this.#equalityComparer.equals(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
export const looseAsyncEqualityComparer: AsyncEqualityComparer<any> = new class LooseAsyncEqualityComparer extends BaseAsyncEqualityComparer<any> {
|
||||
public override async equals(a: any, b: any): Promise<boolean> {
|
||||
return a == b;
|
||||
}
|
||||
};
|
||||
export const strictAsyncEqualityComparer: AsyncEqualityComparer<any> = new class StrictAsyncEqualityComparer extends BaseAsyncEqualityComparer<any> {
|
||||
public override async equals(a: any, b: any): Promise<boolean> {
|
||||
return a === b;
|
||||
}
|
||||
};
|
||||
export const sameValueAsyncEqualityComparer: AsyncEqualityComparer<any> = new class SameValueAsyncEqualityComparer extends BaseAsyncEqualityComparer<any> {
|
||||
public override async equals(a: any, b: any): Promise<boolean> {
|
||||
return Object.is(a, b);
|
||||
}
|
||||
};
|
||||
|
||||
export const defaultAsyncEqualityComparer: AsyncEqualityComparer<any> = new class DefaultAsyncEqualityComparer extends BaseAsyncEqualityComparer<any> {
|
||||
public override async equals(a: any, b: any): Promise<boolean> {
|
||||
return a === b;
|
||||
}
|
||||
};
|
||||
|
||||
export function getDefaultAsyncEqualityComparer<T>(): AsyncEqualityComparer<T> {
|
||||
return defaultAsyncEqualityComparer;
|
||||
}
|
||||
|
||||
export const dateAsyncEqualityComparer: AsyncEqualityComparer<Date> = new class DateAsyncEqualityComparer extends BaseAsyncEqualityComparer<Date> {
|
||||
public override async equals(a: Date, b: Date): Promise<boolean> {
|
||||
return a.getTime() === b.getTime();
|
||||
}
|
||||
};
|
||||
@@ -2,30 +2,14 @@ import { Converter } from "../types.js";
|
||||
import { Nullable } from "../utils.js";
|
||||
import { EqualityComparer, EqualityComparison, EqualityComparisonOrComparer } from "./types.js";
|
||||
|
||||
export function looseEquals(a: any, b: any) {
|
||||
return a == b;
|
||||
}
|
||||
|
||||
export function strictEquals(a: any, b: any) {
|
||||
return a === b;
|
||||
}
|
||||
|
||||
export function sameValue(a: any, b: any) {
|
||||
return Object.is(a, b);
|
||||
}
|
||||
|
||||
export function isEqualityComparer<T>(obj: any): obj is EqualityComparer<T> {
|
||||
return obj instanceof BaseEqualityComparer;
|
||||
}
|
||||
|
||||
export function asEqualityComparer<T>(equalityComparer: EqualityComparisonOrComparer<T>) {
|
||||
export function asEqualityComparer<T>(equalityComparer: EqualityComparisonOrComparer<T>): EqualityComparer<T> {
|
||||
return typeof equalityComparer === "function" ? createEqualityComparer(equalityComparer) : equalityComparer;
|
||||
}
|
||||
|
||||
export function asEqualityComparison<T>(equalityComparer: EqualityComparisonOrComparer<T>) {
|
||||
return typeof equalityComparer === "function" ? equalityComparer : equalityComparer.equalityComparison();
|
||||
}
|
||||
|
||||
export function createEqualityComparer<T = any>(equalityComparison: EqualityComparison<T>): EqualityComparer<T> {
|
||||
return new SimpleEqualityComparer(equalityComparison);
|
||||
}
|
||||
@@ -34,10 +18,6 @@ export function createEqualityComparerUsing<T = any, U = any>(projection: Conver
|
||||
return new MappedEqualityComparer(projection, equalityComparison);
|
||||
}
|
||||
|
||||
export function oppositeEqualityComparison<T>(equalityComparison: EqualityComparison<T>): EqualityComparison<T> {
|
||||
return (a, b) => !equalityComparison(a, b);
|
||||
}
|
||||
|
||||
export function combineNullableEqualityComparers<T>(equalityComparers: Nullable<EqualityComparisonOrComparer<T>>[]) {
|
||||
let result = defaultEqualityComparer;
|
||||
|
||||
@@ -146,6 +126,22 @@ class ThenEqualityComparer<T> extends BaseEqualityComparer<T> {
|
||||
}
|
||||
}
|
||||
|
||||
export const looseEqualityComparer: EqualityComparer<any> = new class LooseEqualityComparer extends BaseEqualityComparer<any> {
|
||||
public override equals(a: any, b: any): boolean {
|
||||
return a == b;
|
||||
}
|
||||
};
|
||||
export const strictEqualityComparer: EqualityComparer<any> = new class StrictEqualityComparer extends BaseEqualityComparer<any> {
|
||||
public override equals(a: any, b: any): boolean {
|
||||
return a === b;
|
||||
}
|
||||
};
|
||||
export const sameValueEqualityComparer: EqualityComparer<any> = new class SameValueEqualityComparer extends BaseEqualityComparer<any> {
|
||||
public override equals(a: any, b: any): boolean {
|
||||
return Object.is(a, b);
|
||||
}
|
||||
};
|
||||
|
||||
export const defaultEqualityComparer: EqualityComparer<any> = new class DefaultEqualityComparer extends BaseEqualityComparer<any> {
|
||||
public override equals(a: any, b: any): boolean {
|
||||
return a === b;
|
||||
@@ -161,7 +157,3 @@ export const dateEqualityComparer: EqualityComparer<Date> = new class DateEquali
|
||||
return a.getTime() === b.getTime();
|
||||
}
|
||||
};
|
||||
|
||||
export const looseEqualityComparer: EqualityComparer<any> = new SimpleEqualityComparer<any>(looseEquals);
|
||||
export const strictEqualityComparer: EqualityComparer<any> = new SimpleEqualityComparer<any>(strictEquals);
|
||||
export const sameValueEqualityComparer: EqualityComparer<any> = new SimpleEqualityComparer<any>(sameValue);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Converter, MaybeAsyncFunction } from "../types.js";
|
||||
import { AsyncFunction, Converter, MaybeAsyncConverter, MaybeAsyncFunction } from "../types.js";
|
||||
|
||||
export interface EqualityComparer<T> {
|
||||
equals(a: T, b: T): boolean;
|
||||
@@ -9,7 +9,20 @@ export interface EqualityComparer<T> {
|
||||
thenEqualsUsing<U>(projection: Converter<T, U>, equalityComparison?: EqualityComparisonOrComparer<U>): EqualityComparer<T>;
|
||||
}
|
||||
|
||||
export interface AsyncEqualityComparer<T> {
|
||||
equals(a: T, b: T): Promise<boolean>;
|
||||
equalityComparison(): AsyncEqualityComparison<T>;
|
||||
opposite(): AsyncEqualityComparer<T>;
|
||||
then(equalityComparer: AsyncEqualityComparer<T>): AsyncEqualityComparer<T>;
|
||||
thenEquals(equalityComparison: AsyncEqualityComparison<T>): AsyncEqualityComparer<T>;
|
||||
thenEqualsUsing<U>(projection: MaybeAsyncConverter<T, U>, equalityComparison?: AsyncEqualityComparisonOrComparer<U>): AsyncEqualityComparer<T>;
|
||||
}
|
||||
|
||||
export type EqualityComparison<T> = (first: T, second: T) => boolean;
|
||||
export type EqualityComparisonOrComparer<T> = EqualityComparison<T> | EqualityComparer<T>;
|
||||
|
||||
export type AsyncEqualityComparison<T> = AsyncFunction<EqualityComparison<T>>;
|
||||
export type MaybeAsyncEqualityComparison<T> = MaybeAsyncFunction<EqualityComparison<T>>;
|
||||
export type AsyncEqualityComparisonOrComparer<T> = AsyncEqualityComparison<T> | AsyncEqualityComparer<T>;
|
||||
export type MaybeAsyncEqualityComparisonOrComparer<T> = MaybeAsyncEqualityComparison<T> | EqualityComparer<T> | AsyncEqualityComparer<T>;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user