1
0

properly implement comparer and equality comparer combination

This commit is contained in:
2025-10-28 16:12:34 +01:00
parent 4e5dfd7134
commit bdea643256
6 changed files with 142 additions and 18 deletions

View File

@@ -1,5 +1,5 @@
import { Collector } from "../collector/types.js"; import { Collector } from "../collector/types.js";
import { asAsyncComparer, combineNullableAsyncComparers, createAsyncComparerUsing, defaultAsyncComparer } from "../comparer/async.js"; import { asAsyncComparer, combineAsyncComparers, createAsyncComparerUsing, defaultAsyncComparer } from "../comparer/async.js";
import { MaybeAsyncComparisonOrComparer, AsyncComparer } from "../comparer/types.js"; import { MaybeAsyncComparisonOrComparer, AsyncComparer } from "../comparer/types.js";
import { asAsyncEqualityComparer, defaultAsyncEqualityComparer } from "../equality-comparer/async.js"; import { asAsyncEqualityComparer, defaultAsyncEqualityComparer } from "../equality-comparer/async.js";
import { AsyncEqualityComparer, MaybeAsyncEqualityComparisonOrComparer } from "../equality-comparer/types.js"; import { AsyncEqualityComparer, MaybeAsyncEqualityComparisonOrComparer } from "../equality-comparer/types.js";
@@ -1713,13 +1713,13 @@ class OrderByAsyncSequence<T, U> extends BaseOrderedAsyncSequence<T> {
class ThenOrderAsyncSequence<T> extends BaseOrderedAsyncSequence<T> { class ThenOrderAsyncSequence<T> extends BaseOrderedAsyncSequence<T> {
constructor(sequence: OrderedAsyncSequence<T>, descending: boolean, sorter?: MaybeAsyncComparisonOrComparer<T>) { constructor(sequence: OrderedAsyncSequence<T>, descending: boolean, sorter?: MaybeAsyncComparisonOrComparer<T>) {
super(sequence, combineNullableAsyncComparers([sequence.comparer, sorter]), descending); super(sequence, combineAsyncComparers([sequence.comparer, sorter]), descending);
} }
} }
class ThenOrderByAsyncSequence<T, U> extends BaseOrderedAsyncSequence<T> { class ThenOrderByAsyncSequence<T, U> extends BaseOrderedAsyncSequence<T> {
constructor(sequence: OrderedAsyncSequence<T>, descending: boolean, selector: MaybeAsyncConverter<T, U>, sorter?: MaybeAsyncComparisonOrComparer<U>) { constructor(sequence: OrderedAsyncSequence<T>, descending: boolean, selector: MaybeAsyncConverter<T, U>, sorter?: MaybeAsyncComparisonOrComparer<U>) {
super(sequence, combineNullableAsyncComparers([sequence.comparer, createAsyncComparerUsing(selector, sorter)]), descending); super(sequence, combineAsyncComparers([sequence.comparer, createAsyncComparerUsing(selector, sorter)]), descending);
} }
} }

View File

@@ -22,8 +22,8 @@ export function createAsyncComparerUsing<T, U>(projection: MaybeAsyncConverter<T
return new MappedAsyncComparer(projection, comparison); return new MappedAsyncComparer(projection, comparison);
} }
export function combineNullableAsyncComparers<T>(comparers: Nullable<MaybeAsyncComparisonOrComparer<T>>[]): AsyncComparer<T> | undefined { export function combineAsyncComparers<T>(comparers: Iterable<Nullable<MaybeAsyncComparisonOrComparer<T>>>): AsyncComparer<T> | undefined {
let result = defaultAsyncComparer; let result: AsyncComparer<T> = dummyAsyncComparer;
for (const comparer of comparers) { for (const comparer of comparers) {
if (!comparer) { if (!comparer) {
@@ -33,7 +33,7 @@ export function combineNullableAsyncComparers<T>(comparers: Nullable<MaybeAsyncC
result = result.then(asAsyncComparer(comparer)); result = result.then(asAsyncComparer(comparer));
} }
return result === defaultAsyncComparer ? undefined : result; return result === dummyAsyncComparer ? undefined : result;
} }
export abstract class BaseAsyncComparer<T> implements AsyncComparer<T> { export abstract class BaseAsyncComparer<T> implements AsyncComparer<T> {
@@ -144,6 +144,24 @@ class ThenAsyncComparer<T> extends BaseAsyncComparer<T> {
} }
} }
const dummyAsyncComparer = new class DummyAsyncComparer extends BaseAsyncComparer<any> {
public override async compare(_a: any, _b: any): Promise<number> {
return 0;
}
public override then(comparer: AsyncComparer<any>): AsyncComparer<any> {
return comparer;
}
public override thenCompare(comparison: MaybeAsyncComparison<any>): AsyncComparer<any> {
return createAsyncComparer(comparison);
}
public override thenCompareUsing<U>(projection: MaybeAsyncConverter<any, U>, comparison?: MaybeAsyncComparisonOrComparer<U> | undefined): AsyncComparer<any> {
return createAsyncComparerUsing(projection, comparison);
}
}
export const defaultAsyncComparer: AsyncComparer<any> = new class DefaultAsyncComparer extends BaseAsyncComparer<any> { export const defaultAsyncComparer: AsyncComparer<any> = new class DefaultAsyncComparer extends BaseAsyncComparer<any> {
public override async compare(a: any, b: any): Promise<number> { public override async compare(a: any, b: any): Promise<number> {
if (a === undefined) { if (a === undefined) {

View File

@@ -27,8 +27,8 @@ export function reverseComparison<T>(comparison: Comparison<T>): Comparison<T> {
return (a, b) => comparison(b, a); return (a, b) => comparison(b, a);
} }
export function combineNullableComparers<T>(comparers: Nullable<ComparisonOrComparer<T>>[]) { export function combineComparers<T>(comparers: Iterable<Nullable<ComparisonOrComparer<T>>>) {
let result = defaultComparer; let result: Comparer<T> = dummyComparer;
for (const comparer of comparers) { for (const comparer of comparers) {
if (!comparer) { if (!comparer) {
@@ -38,7 +38,7 @@ export function combineNullableComparers<T>(comparers: Nullable<ComparisonOrComp
result = result.then(asComparer(comparer)); result = result.then(asComparer(comparer));
} }
return result === defaultComparer ? undefined : result; return result === dummyComparer ? undefined : result;
} }
export abstract class BaseComparer<T> implements Comparer<T> { export abstract class BaseComparer<T> implements Comparer<T> {
@@ -75,6 +75,24 @@ export abstract class BaseComparer<T> implements Comparer<T> {
} }
} }
const dummyComparer = new class DummyComparer extends BaseComparer<any> {
public override compare(_a: any, _b: any): number {
return 0;
}
public override then(comparer: Comparer<any>): Comparer<any> {
return comparer;
}
public override thenCompare(comparison: Comparison<any>): Comparer<any> {
return createComparer(comparison);
}
public override thenCompareUsing<U>(projection: Converter<any, U>, comparison?: ComparisonOrComparer<U> | undefined): Comparer<any> {
return createComparerUsing(projection, comparison);
}
};
class SimpleComparer<T> extends BaseComparer<T> { class SimpleComparer<T> extends BaseComparer<T> {
readonly #comparison: Comparison<T>; readonly #comparison: Comparison<T>;

View File

@@ -22,8 +22,8 @@ export function createAsyncEqualityComparerUsing<T = any, U = any>(projection: M
return new MappedAsyncEqualityComparer(projection, equalityComparison); return new MappedAsyncEqualityComparer(projection, equalityComparison);
} }
export function combineNullableAsyncEqualityComparers<T>(equalityComparers: Nullable<MaybeAsyncEqualityComparisonOrComparer<T>>[]) { export function combineAsyncEqualityComparers<T>(equalityComparers: Iterable<Nullable<MaybeAsyncEqualityComparisonOrComparer<T>>>) {
let result = defaultAsyncEqualityComparer; let result: AsyncEqualityComparer<T> = alwaysTrueAsyncEqualityComparer;
for (const equalityComparer of equalityComparers) { for (const equalityComparer of equalityComparers) {
if (!equalityComparer) { if (!equalityComparer) {
@@ -33,7 +33,7 @@ export function combineNullableAsyncEqualityComparers<T>(equalityComparers: Null
result = result.then(asAsyncEqualityComparer(equalityComparer)); result = result.then(asAsyncEqualityComparer(equalityComparer));
} }
return result === defaultAsyncEqualityComparer ? undefined : result; return result === alwaysTrueAsyncEqualityComparer ? undefined : result;
} }
export abstract class BaseAsyncEqualityComparer<T> implements AsyncEqualityComparer<T> { export abstract class BaseAsyncEqualityComparer<T> implements AsyncEqualityComparer<T> {
@@ -140,6 +140,50 @@ class ThenAsyncEqualityComparer<T> extends BaseAsyncEqualityComparer<T> {
} }
} }
export const alwaysAsyncFalseEqualityComparer = new class AlwaysFalseAsyncEqualityComparer extends BaseAsyncEqualityComparer<any> {
public override async equals(_a: any, _b: any): Promise<boolean> {
return false;
}
public override opposite(): AsyncEqualityComparer<any> {
return alwaysTrueAsyncEqualityComparer;
}
public override then(_equalityComparer: AsyncEqualityComparer<any>): AsyncEqualityComparer<any> {
return this;
}
public override thenEquals(_equalityComparison: MaybeAsyncEqualityComparison<any>): AsyncEqualityComparer<any> {
return this;
}
public override thenEqualsUsing<U>(_projection: MaybeAsyncConverter<any, U>, _equalityComparison?: MaybeAsyncEqualityComparisonOrComparer<U> | undefined): AsyncEqualityComparer<any> {
return this;
}
};
export const alwaysTrueAsyncEqualityComparer = new class AlwaysTrueAsyncEqualityComparer extends BaseAsyncEqualityComparer<any> {
public override async equals(_a: any, _b: any): Promise<boolean> {
return true;
}
public override opposite(): AsyncEqualityComparer<any> {
return alwaysAsyncFalseEqualityComparer;
}
public override then(equalityComparer: AsyncEqualityComparer<any>): AsyncEqualityComparer<any> {
return equalityComparer;
}
public override thenEquals(equalityComparison: MaybeAsyncEqualityComparison<any>): AsyncEqualityComparer<any> {
return createAsyncEqualityComparer(equalityComparison);
}
public override thenEqualsUsing<U>(projection: MaybeAsyncConverter<any, U>, equalityComparison?: MaybeAsyncEqualityComparisonOrComparer<U> | undefined): AsyncEqualityComparer<any> {
return createAsyncEqualityComparerUsing(projection, equalityComparison);
}
};
export const looseAsyncEqualityComparer: AsyncEqualityComparer<any> = new class LooseAsyncEqualityComparer extends BaseAsyncEqualityComparer<any> { export const looseAsyncEqualityComparer: AsyncEqualityComparer<any> = new class LooseAsyncEqualityComparer extends BaseAsyncEqualityComparer<any> {
public override async equals(a: any, b: any): Promise<boolean> { public override async equals(a: any, b: any): Promise<boolean> {
return a == b; return a == b;

View File

@@ -18,8 +18,8 @@ export function createEqualityComparerUsing<T = any, U = any>(projection: Conver
return new MappedEqualityComparer(projection, equalityComparison); return new MappedEqualityComparer(projection, equalityComparison);
} }
export function combineNullableEqualityComparers<T>(equalityComparers: Nullable<EqualityComparisonOrComparer<T>>[]) { export function combineEqualityComparers<T>(equalityComparers: Iterable<Nullable<EqualityComparisonOrComparer<T>>>) {
let result = defaultEqualityComparer; let result: EqualityComparer<T> = alwaysTrueEqualityComparer;
for (const equalityComparer of equalityComparers) { for (const equalityComparer of equalityComparers) {
if (!equalityComparer) { if (!equalityComparer) {
@@ -29,7 +29,7 @@ export function combineNullableEqualityComparers<T>(equalityComparers: Nullable<
result = result.then(asEqualityComparer(equalityComparer)); result = result.then(asEqualityComparer(equalityComparer));
} }
return result === defaultEqualityComparer ? undefined : result; return result === alwaysTrueEqualityComparer ? undefined : result;
} }
export abstract class BaseEqualityComparer<T> implements EqualityComparer<T> { export abstract class BaseEqualityComparer<T> implements EqualityComparer<T> {
@@ -126,6 +126,50 @@ class ThenEqualityComparer<T> extends BaseEqualityComparer<T> {
} }
} }
export const alwaysFalseEqualityComparer = new class AlwaysFalseEqualityComparer extends BaseEqualityComparer<any> {
public override equals(_a: any, _b: any): boolean {
return false;
}
public override opposite(): EqualityComparer<any> {
return alwaysTrueEqualityComparer;
}
public override then(_equalityComparer: EqualityComparer<any>): EqualityComparer<any> {
return this;
}
public override thenEquals(_equalityComparison: EqualityComparison<any>): EqualityComparer<any> {
return this;
}
public override thenEqualsUsing<U>(_projection: Converter<any, U>, _equalityComparison?: EqualityComparisonOrComparer<U> | undefined): EqualityComparer<any> {
return this;
}
};
export const alwaysTrueEqualityComparer = new class AlwaysTrueEqualityComparer extends BaseEqualityComparer<any> {
public override equals(_a: any, _b: any): boolean {
return true;
}
public override opposite(): EqualityComparer<any> {
return alwaysFalseEqualityComparer;
}
public override then(equalityComparer: EqualityComparer<any>): EqualityComparer<any> {
return equalityComparer;
}
public override thenEquals(equalityComparison: EqualityComparison<any>): EqualityComparer<any> {
return createEqualityComparer(equalityComparison);
}
public override thenEqualsUsing<U>(projection: Converter<any, U>, equalityComparison?: EqualityComparisonOrComparer<U> | undefined): EqualityComparer<any> {
return createEqualityComparerUsing(projection, equalityComparison);
}
};
export const looseEqualityComparer: EqualityComparer<any> = new class LooseEqualityComparer extends BaseEqualityComparer<any> { export const looseEqualityComparer: EqualityComparer<any> = new class LooseEqualityComparer extends BaseEqualityComparer<any> {
public override equals(a: any, b: any): boolean { public override equals(a: any, b: any): boolean {
return a == b; return a == b;

View File

@@ -1,7 +1,7 @@
import { BaseAsyncSequence } from "../async/impl.js"; import { BaseAsyncSequence } from "../async/impl.js";
import { AsyncSequence } from "../async/types.js"; import { AsyncSequence } from "../async/types.js";
import { Collector } from "../collector/types.js"; import { Collector } from "../collector/types.js";
import { asComparer, combineNullableComparers, createComparerUsing, defaultComparer } from "../comparer/sync.js"; import { asComparer, combineComparers, createComparerUsing, defaultComparer } from "../comparer/sync.js";
import { ComparisonOrComparer, Comparer } from "../comparer/types.js"; import { ComparisonOrComparer, Comparer } from "../comparer/types.js";
import { asEqualityComparer, defaultEqualityComparer } from "../equality-comparer/sync.js"; import { asEqualityComparer, defaultEqualityComparer } from "../equality-comparer/sync.js";
import { EqualityComparer, EqualityComparisonOrComparer } from "../equality-comparer/types.js"; import { EqualityComparer, EqualityComparisonOrComparer } from "../equality-comparer/types.js";
@@ -1974,13 +1974,13 @@ class OrderBySequence<T, U> extends BaseOrderedSequence<T> {
class ThenOrderSequence<T> extends BaseOrderedSequence<T> { class ThenOrderSequence<T> extends BaseOrderedSequence<T> {
constructor(sequence: OrderedSequence<T>, descending: boolean, sorter?: ComparisonOrComparer<T>) { constructor(sequence: OrderedSequence<T>, descending: boolean, sorter?: ComparisonOrComparer<T>) {
super(sequence, combineNullableComparers([sequence.comparer, sorter]), descending); super(sequence, combineComparers([sequence.comparer, sorter]), descending);
} }
} }
class ThenOrderBySequence<T, U> extends BaseOrderedSequence<T> { class ThenOrderBySequence<T, U> extends BaseOrderedSequence<T> {
constructor(sequence: OrderedSequence<T>, descending: boolean, selector: Converter<T, U>, sorter?: ComparisonOrComparer<U>) { constructor(sequence: OrderedSequence<T>, descending: boolean, selector: Converter<T, U>, sorter?: ComparisonOrComparer<U>) {
super(sequence, combineNullableComparers([sequence.comparer, createComparerUsing(selector, sorter)]), descending); super(sequence, combineComparers([sequence.comparer, createComparerUsing(selector, sorter)]), descending);
} }
} }