geninq
Version:
A JavaScript version of the Linq library for Generators
148 lines (141 loc) • 3.99 kB
text/typescript
import { Build, Promised } from "./utils";
import "./select";
import "./array";
import {
Assert,
IsFunction,
IsNumber,
IsString,
IsTuple,
IsUnion,
PatternMatch,
} from "@paulpopat/safe-type";
declare global {
interface Generator<T = unknown, TReturn = any, TNext = unknown> {
order_by(
this: Generator<number, TReturn, TNext>,
descending?: "descending"
): Generator<T, TReturn, TNext>;
order_by(
this: Generator<string, TReturn, TNext>,
descending?: "descending"
): Generator<T, TReturn, TNext>;
order_by(
key_selector: (item: T) => number,
descending?: "descending"
): Generator<T, TReturn, TNext>;
order_by(
key_selector: (item: T) => string,
descending?: "descending"
): Generator<T, TReturn, TNext>;
order_by<TKey>(
key_selector: (item: T) => TKey,
comparitor: (a: TKey, b: TKey) => boolean,
descending?: "descending"
): Generator<T, TReturn, TNext>;
}
interface AsyncGenerator<T = unknown, TReturn = any, TNext = unknown> {
order_by(
this: AsyncGenerator<number, TReturn, TNext>,
descending?: "descending"
): AsyncGenerator<T, TReturn, TNext>;
order_by(
this: AsyncGenerator<string, TReturn, TNext>,
descending?: "descending"
): AsyncGenerator<T, TReturn, TNext>;
order_by(
key_selector: (item: T) => Promised<number>,
descending?: "descending"
): AsyncGenerator<T, TReturn, TNext>;
order_by(
key_selector: (item: T) => Promised<string>,
descending?: "descending"
): AsyncGenerator<T, TReturn, TNext>;
order_by<TKey>(
key_selector: (item: T) => Promised<TKey>,
comparitor: (a: TKey, b: TKey) => boolean,
descending?: "descending"
): AsyncGenerator<T, TReturn, TNext>;
}
}
function BuildArguments(args: IArguments): {
key_selector: <T>(i: T) => T;
comparitor: (a: unknown, b: unknown) => boolean;
descending: boolean;
} {
const default_key_selector = <T>(i: T) => i;
const default_comparitor = (a: unknown, b: unknown) => {
Assert(IsUnion(IsString, IsNumber), a);
Assert(IsUnion(IsString, IsNumber), b);
return a > b;
};
if (args.length === 0) {
return {
key_selector: default_key_selector,
comparitor: default_comparitor,
descending: false,
};
}
return PatternMatch(
IsTuple(IsString),
IsTuple(IsFunction, IsString),
IsTuple(IsFunction, IsFunction, IsString),
IsTuple(IsFunction),
IsTuple(IsFunction, IsFunction)
)(
([descending]) => ({
key_selector: default_key_selector,
comparitor: default_comparitor,
descending: descending != null,
}),
([key_selector, descending]) => ({
key_selector,
comparitor: default_comparitor,
descending: descending != null,
}),
([key_selector, comparitor, descending]) => ({
key_selector,
comparitor,
descending: descending != null,
}),
([key_selector]) => ({
key_selector,
comparitor: default_comparitor,
descending: false,
}),
([key_selector, comparitor]) => ({
key_selector,
comparitor,
descending: false,
})
)([...args] as any) as any;
}
Build(
"order_by",
function* () {
const m = BuildArguments(arguments);
let new_subject = this.select((i) => [m.key_selector(i), i] as const)
.array()
.sort(([a], [b]) => (m.comparitor(a, b) ? 1 : -1));
if (m.descending) {
new_subject = new_subject.reverse();
}
for (const item of new_subject) {
yield item[1];
}
},
async function* () {
const m = BuildArguments(arguments);
let new_subject = (
await this.select(
async (i) => [await m.key_selector(i), i] as const
).array()
).sort(([a], [b]) => (m.comparitor(a, b) ? 1 : -1));
if (m.descending) {
new_subject = new_subject.reverse();
}
for (const item of new_subject) {
yield item[1];
}
}
);