From b0bd01dc9dd3acf2b2bc5b7344a6f3afc65f9582 Mon Sep 17 00:00:00 2001 From: Ilya Gonchar Date: Fri, 21 Nov 2025 01:52:11 +0100 Subject: [PATCH] added support key param for sortBy and sortByDescending --- README.md | 11 ++++------- src/operators/async/sortedBy.ts | 12 +++++++++++- src/operators/async/sortedByDescending.ts | 12 +++++++++++- src/operators/sync/sortedBy.ts | 12 +++++++++++- src/operators/sync/sortedByDescending.ts | 12 +++++++++++- test/operators/async/sortedBy.test.ts | 13 +++++++++++++ test/operators/async/sortedByDescending.test.ts | 15 ++++++++++++++- test/operators/sync/sortedBy.test.ts | 13 +++++++++++++ test/operators/sync/sortedByDescending.test.ts | 15 ++++++++++++++- 9 files changed, 102 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 069c892..5f64f76 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,7 @@ --- -

-★★★ Like this project? Leave a star and follow on Twitter! Thanks. ★★★ -

+**★★★ Like this project? [Leave a star](https://github.com/winterbe/sequency/stargazers) and [follow on Twitter](https://twitter.com/winterbe_)! Thanks. ★★★** ## About Sequency @@ -18,7 +16,6 @@ Sequency is a lightweight (**5 KB minified**), intensely tested (**200+ tests, 9 ## Getting started - ```bash npm install --save sequency ``` @@ -61,19 +58,19 @@ Sequences are **lazily evaluated** to avoid examining all of the input data when ### Core Components -**Sequence** — The central interface of the library: +**`Sequence`** — The central interface of the library: - Contains a single `iterator: Iterator` property for lazy iteration - Extends `SequenceOperators`, which combines all operations - Sequences can be iterated only once (single-pass) -**SequenceImpl** — The concrete implementation using the **Mixin Pattern**: +**`SequenceImpl`** — The concrete implementation using the **Mixin Pattern**: - All operations are added dynamically via the `applyMixins()` function - Each operation is implemented as a separate mixin class - Enables modular code organization and easy addition of new operations -**AsyncSequence** — Asynchronous version of the sequence: +**`AsyncSequence`** — Asynchronous version of the sequence: - Uses `AsyncIterator` instead of `Iterator` - All operations return `Promise` diff --git a/src/operators/async/sortedBy.ts b/src/operators/async/sortedBy.ts index de1a81d..4cd5c1c 100644 --- a/src/operators/async/sortedBy.ts +++ b/src/operators/async/sortedBy.ts @@ -1,4 +1,5 @@ import {AsyncSequence} from "../../sequency"; +import {asAsyncSelector} from "../../internal"; export class SortedBy { @@ -9,7 +10,16 @@ export class SortedBy { * @param {(value: T) => Promise | R} selector * @returns {AsyncSequence} */ - sortedBy(this: AsyncSequence, selector: (value: T) => Promise | R): AsyncSequence { + sortedBy(this: AsyncSequence, selector: (value: T) => Promise | R): AsyncSequence; + /** + * Returns a new sequence with all elements sorted ascending by the value of the given `key`. + * + * @param {keyof T} key + * @returns {AsyncSequence} + */ + sortedBy(this: AsyncSequence, key: keyof NonNullable): AsyncSequence; + sortedBy(this: AsyncSequence, keyOrSelector: ((value: T) => Promise | R) | keyof NonNullable): AsyncSequence { + const selector = asAsyncSelector(keyOrSelector); return this.sorted(it => it.compareBy(selector)); } diff --git a/src/operators/async/sortedByDescending.ts b/src/operators/async/sortedByDescending.ts index cf923cf..d8d9ad5 100644 --- a/src/operators/async/sortedByDescending.ts +++ b/src/operators/async/sortedByDescending.ts @@ -1,4 +1,5 @@ import {AsyncSequence} from "../../sequency"; +import {asAsyncSelector} from "../../internal"; export class SortedByDescending { @@ -9,7 +10,16 @@ export class SortedByDescending { * @param {(value: T) => Promise | R} selector * @returns {AsyncSequence} */ - sortedByDescending(this: AsyncSequence, selector: (value: T) => Promise | R): AsyncSequence { + sortedByDescending(this: AsyncSequence, selector: (value: T) => Promise | R): AsyncSequence; + /** + * Returns a new sequence with all elements sorted descending by the value of the given `key`. + * + * @param {keyof T} key + * @returns {AsyncSequence} + */ + sortedByDescending(this: AsyncSequence, key: keyof NonNullable): AsyncSequence; + sortedByDescending(this: AsyncSequence, keyOrSelector: ((value: T) => Promise | R) | keyof NonNullable): AsyncSequence { + const selector = asAsyncSelector(keyOrSelector); return this.sorted(it => it.compareByDescending(selector)); } diff --git a/src/operators/sync/sortedBy.ts b/src/operators/sync/sortedBy.ts index a8b093f..62f5330 100644 --- a/src/operators/sync/sortedBy.ts +++ b/src/operators/sync/sortedBy.ts @@ -1,4 +1,5 @@ import {Sequence} from "../../sequency"; +import {asSelector} from "../../internal"; export class SortedBy { @@ -9,7 +10,16 @@ export class SortedBy { * @param {(value: T) => R} selector * @returns {Sequence} */ - sortedBy(this: Sequence, selector: (value: T) => R): Sequence { + sortedBy(this: Sequence, selector: (value: T) => R): Sequence; + /** + * Returns a new sequence with all elements sorted ascending by the value of the given `key`. + * + * @param {keyof T} key + * @returns {Sequence} + */ + sortedBy(this: Sequence, key: keyof NonNullable): Sequence; + sortedBy(this: Sequence, keyOrSelector: ((value: T) => R) | keyof NonNullable): Sequence { + const selector = asSelector(keyOrSelector); return this.sorted(it => it.compareBy(selector)); } diff --git a/src/operators/sync/sortedByDescending.ts b/src/operators/sync/sortedByDescending.ts index 098a1d2..56a2001 100644 --- a/src/operators/sync/sortedByDescending.ts +++ b/src/operators/sync/sortedByDescending.ts @@ -1,4 +1,5 @@ import {Sequence} from "../../sequency"; +import {asSelector} from "../../internal"; export class SortedByDescending { @@ -9,7 +10,16 @@ export class SortedByDescending { * @param {(value: T) => R} selector * @returns {Sequence} */ - sortedByDescending(this: Sequence, selector: (value: T) => R): Sequence { + sortedByDescending(this: Sequence, selector: (value: T) => R): Sequence; + /** + * Returns a new sequence with all elements sorted descending by the value of the given `key`. + * + * @param {keyof T} key + * @returns {Sequence} + */ + sortedByDescending(this: Sequence, key: keyof NonNullable): Sequence; + sortedByDescending(this: Sequence, keyOrSelector: ((value: T) => R) | keyof NonNullable): Sequence { + const selector = asSelector(keyOrSelector); return this.sorted(it => it.compareByDescending(selector)); } diff --git a/test/operators/async/sortedBy.test.ts b/test/operators/async/sortedBy.test.ts index e5c4e9c..40f1531 100644 --- a/test/operators/async/sortedBy.test.ts +++ b/test/operators/async/sortedBy.test.ts @@ -13,4 +13,17 @@ describe("sortedBy", () => { expect(array).toEqual([a1, a3, a4, a23]); }); + + it("should sort by the given key string ascending", async () => { + const a4 = {a: 4}; + const a1 = {a: 1}; + const a3 = {a: 3}; + const a23 = {a: 23}; + + const array = await asyncSequenceOf(a4, a1, a3, a23) + .sortedBy("a") + .toArray(); + + expect(array).toEqual([a1, a3, a4, a23]); + }); }); \ No newline at end of file diff --git a/test/operators/async/sortedByDescending.test.ts b/test/operators/async/sortedByDescending.test.ts index 948086d..5c7e198 100644 --- a/test/operators/async/sortedByDescending.test.ts +++ b/test/operators/async/sortedByDescending.test.ts @@ -1,6 +1,6 @@ import {asyncSequenceOf} from "../../../src/sequency"; -describe("sortedBy", () => { +describe("sortedByDescending", () => { it("should sort by the given key descending", async () => { const a4 = {a: 4}; const a1 = {a: 1}; @@ -13,4 +13,17 @@ describe("sortedBy", () => { expect(array).toEqual([a23, a4, a3, a1]); }); + + it("should sort by the given key string descending", async () => { + const a4 = {a: 4}; + const a1 = {a: 1}; + const a3 = {a: 3}; + const a23 = {a: 23}; + + const array = await asyncSequenceOf(a4, a1, a3, a23) + .sortedByDescending("a") + .toArray(); + + expect(array).toEqual([a23, a4, a3, a1]); + }); }); \ No newline at end of file diff --git a/test/operators/sync/sortedBy.test.ts b/test/operators/sync/sortedBy.test.ts index 3d44b08..c9545c4 100644 --- a/test/operators/sync/sortedBy.test.ts +++ b/test/operators/sync/sortedBy.test.ts @@ -13,4 +13,17 @@ describe("sortedBy", () => { expect(array).toEqual([a1, a3, a4, a23]); }); + + it("should sort by the given key string ascending", () => { + const a4 = {a: 4}; + const a1 = {a: 1}; + const a3 = {a: 3}; + const a23 = {a: 23}; + + const array = sequenceOf(a4, a1, a3, a23) + .sortedBy("a") + .toArray(); + + expect(array).toEqual([a1, a3, a4, a23]); + }); }); \ No newline at end of file diff --git a/test/operators/sync/sortedByDescending.test.ts b/test/operators/sync/sortedByDescending.test.ts index feef60d..6ee7aa8 100644 --- a/test/operators/sync/sortedByDescending.test.ts +++ b/test/operators/sync/sortedByDescending.test.ts @@ -1,6 +1,6 @@ import {sequenceOf} from "../../../src/sequency"; -describe("sortedBy", () => { +describe("sortedByDescending", () => { it("should sort by the given key descending", () => { const a4 = {a: 4}; const a1 = {a: 1}; @@ -13,4 +13,17 @@ describe("sortedBy", () => { expect(array).toEqual([a23, a4, a3, a1]); }); + + it("should sort by the given key string descending", () => { + const a4 = {a: 4}; + const a1 = {a: 1}; + const a3 = {a: 3}; + const a23 = {a: 23}; + + const array = sequenceOf(a4, a1, a3, a23) + .sortedByDescending("a") + .toArray(); + + expect(array).toEqual([a23, a4, a3, a1]); + }); }); \ No newline at end of file