Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ import {
- `generateSequence` returns a sequence generated from the given generator function.
- `extendSequence` allows extending sequences with user-defined operations (see [example](https://github.com/Kraken-crypto/sequency/blob/master/test/extendSequence.test.ts)).

Each `Sequence` provides a fluent functional API consisting of intermediate and terminal operations. Intermediate functions (e.g. `filter`, `map`, `sorted`) return a new sequence, thus enabling method chaining. Terminal functions (e.g. `toArray`, `groupBy`, `findLast`) return an arbitrary result. Detailed descriptions of all operations are available in the [API docs](https://github.com/Kraken-crypto/sequency).
Each `Sequence` provides a fluent functional API consisting of intermediate and terminal operations. Intermediate functions (e.g. `filter`, `map`, `sorted`) return a new sequence, thus enabling method chaining. Terminal functions (e.g. `toArray`, `groupBy`, `findLast`) return an arbitrary result. Detailed descriptions of all operations are available in the [API docs](https://kraken-crypto.github.io/sequency).

Sequences are **lazily evaluated** to avoid examining all of the input data when it's not necessary. Sequences always perform the minimal amount of operations to gain results. E.g. in a `filter - map - find` sequence both `map` and `find` are executed just one time before returning the single result.

Expand Down Expand Up @@ -113,7 +113,9 @@ Sequences are **lazily evaluated** to avoid examining all of the input data when

## API documentation

Sequency is fully documented via inline JSDoc comments. When using an IDE like Intellij IDEA or Webstorm the docs are available inline right inside your editor.
Full API documentation is available at [Sequency API docs](https://kraken-crypto.github.io/sequency).

Sequency is also fully documented via inline JSDoc comments. When using an IDE like Intellij IDEA or Webstorm the docs are available inline right inside your editor.

## Why Sequency?

Expand Down
6 changes: 4 additions & 2 deletions src/AsyncSequence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import {GroupBy as GroupByOp} from "./operators/async/groupBy";
import {IndexOf as IndexOfOp} from "./operators/async/indexOf";
import {IndexOfFirst as IndexOfFirstOp} from "./operators/async/indexOfFirst";
import {IndexOfLast as IndexOfLastOp} from "./operators/async/indexOfLast";
import {IsEmpty as IsEmptyOp} from "./operators/async/isEmpty";
import {IsNotEmpty as IsNotEmptyOp} from "./operators/async/isNotEmpty";
import {JoinToString as JoinToStringOp} from "./operators/async/joinToString";
import {Last as LastOp} from "./operators/async/last";
import {LastOrNull as LastOrNullOp} from "./operators/async/lastOrNull";
Expand Down Expand Up @@ -87,7 +89,7 @@ export interface AsyncSequence<T> extends AsyncSequenceOperators<T> {
*/
export interface AsyncSequenceOperators<T> extends AllOp, AnyOp, AsIterableOp, AssociateOp, AssociateByOp<T>, AverageOp, ChunkOp, ContainsOp, CountOp, DistinctOp, DistinctByOp, DropOp, DropWhileOp,
ElementAtOp, ElementAtOrElseOp, ElementAtOrNullOp, FilterOp, FilterIndexedOp, FilterNotOp, FilterNotNullOp, FirstOp, FirstOrNullOp, FlatMapOp, FlattenOp, FoldOp,
FoldIndexedOp, ForEachOp, ForEachIndexedOp, GroupByOp, IndexOfOp, IndexOfFirstOp, IndexOfLastOp, JoinToStringOp, LastOp, LastOrNullOp, MapOp, MapIndexedOp, MapNotNullOp, MaxOp, MaxByOp,
FoldIndexedOp, ForEachOp, ForEachIndexedOp, GroupByOp, IndexOfOp, IndexOfFirstOp, IndexOfLastOp, IsEmptyOp, IsNotEmptyOp, JoinToStringOp, LastOp, LastOrNullOp, MapOp, MapIndexedOp, MapNotNullOp, MaxOp, MaxByOp,
MaxWithOp, MergeOp, MinOp, MinByOp, MinusOp, MinWithOp, NoneOp, OnEachOp, OnEachIndexedOp, PartitionOp, PlusOp, ReduceOp, ReduceIndexedOp, ReverseOp, SingleOp, SingleOrNullOp, SortedOp,
SortedByOp, SortedByDescendingOp, SortedDescendingOp, SortedWithOp, SumOp, SumByOp, TakeOp, TakeWhileOp, ToArrayOp, ToMapOp, ToSetOp, ToSequenceOp, UnzipOp, WithIndexOp, ZipOp {
}
Expand All @@ -99,6 +101,6 @@ export class AsyncSequenceImpl<T> {

applyMixins(AsyncSequenceImpl, [AllOp, AnyOp, AsIterableOp, AssociateOp, AssociateByOp, AverageOp, ChunkOp, ContainsOp, CountOp, DistinctOp, DistinctByOp, DropOp, DropWhileOp,
ElementAtOp, ElementAtOrElseOp, ElementAtOrNullOp, FilterOp, FilterIndexedOp, FilterNotOp, FilterNotNullOp, FirstOp, FirstOrNullOp, FlatMapOp, FlattenOp, FoldOp,
FoldIndexedOp, ForEachOp, ForEachIndexedOp, GroupByOp, IndexOfOp, IndexOfFirstOp, IndexOfLastOp, JoinToStringOp, LastOp, LastOrNullOp, MapOp, MapIndexedOp, MapNotNullOp, MaxOp, MaxByOp,
FoldIndexedOp, ForEachOp, ForEachIndexedOp, GroupByOp, IndexOfOp, IndexOfFirstOp, IndexOfLastOp, IsEmptyOp, IsNotEmptyOp, JoinToStringOp, LastOp, LastOrNullOp, MapOp, MapIndexedOp, MapNotNullOp, MaxOp, MaxByOp,
MaxWithOp, MergeOp, MinOp, MinByOp, MinusOp, MinWithOp, NoneOp, OnEachOp, OnEachIndexedOp, PartitionOp, PlusOp, ReduceOp, ReduceIndexedOp, ReverseOp, SingleOp, SingleOrNullOp, SortedOp,
SortedByOp, SortedByDescendingOp, SortedDescendingOp, SortedWithOp, SumOp, SumByOp, TakeOp, TakeWhileOp, ToArrayOp, ToMapOp, ToSetOp, ToSequenceOp, UnzipOp, WithIndexOp, ZipOp]);
8 changes: 5 additions & 3 deletions src/Sequence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import {GroupBy as GroupByOp} from "./operators/sync/groupBy";
import {IndexOf as IndexOfOp} from "./operators/sync/indexOf";
import {IndexOfFirst as IndexOfFirstOp} from "./operators/sync/indexOfFirst";
import {IndexOfLast as IndexOfLastOp} from "./operators/sync/indexOfLast";
import {IsEmpty as IsEmptyOp} from "./operators/sync/isEmpty";
import {IsNotEmpty as IsNotEmptyOp} from "./operators/sync/isNotEmpty";
import {JoinToString as JoinToStringOp} from "./operators/sync/joinToString";
import {Last as LastOp} from "./operators/sync/last";
import {LastOrNull as LastOrNullOp} from "./operators/sync/lastOrNull";
Expand Down Expand Up @@ -87,7 +89,7 @@ export interface Sequence<T> extends SequenceOperators<T> {
*/
export interface SequenceOperators<T> extends AllOp, AnyOp, AsIterableOp, AssociateOp, AssociateByOp<T>, AverageOp, ChunkOp, ContainsOp, CountOp, DistinctOp, DistinctByOp, DropOp, DropWhileOp,
ElementAtOp, ElementAtOrElseOp, ElementAtOrNullOp, FilterOp, FilterIndexedOp, FilterNotOp, FilterNotNullOp, FirstOp, FirstOrNullOp, FlatMapOp, FlattenOp, FoldOp,
FoldIndexedOp, ForEachOp, ForEachIndexedOp, GroupByOp, IndexOfOp, IndexOfFirstOp, IndexOfLastOp, JoinToStringOp, LastOp, LastOrNullOp, MapOp, MapIndexedOp, MapNotNullOp, MaxOp, MaxByOp,
FoldIndexedOp, ForEachOp, ForEachIndexedOp, GroupByOp, IndexOfOp, IndexOfFirstOp, IndexOfLastOp, IsEmptyOp, IsNotEmptyOp, JoinToStringOp, LastOp, LastOrNullOp, MapOp, MapIndexedOp, MapNotNullOp, MaxOp, MaxByOp,
MaxWithOp, MergeOp, MinOp, MinByOp, MinusOp, MinWithOp, NoneOp, OnEachOp, OnEachIndexedOp, PartitionOp, PlusOp, ReduceOp, ReduceIndexedOp, ReverseOp, SingleOp, SingleOrNullOp, SortedOp,
SortedByOp, SortedByDescendingOp, SortedDescendingOp, SortedWithOp, SumOp, SumByOp, TakeOp, TakeWhileOp, ToArrayOp, ToAsyncSequenceOp, ToMapOp, ToSetOp, UnzipOp, WithIndexOp, ZipOp {
}
Expand All @@ -99,6 +101,6 @@ export class SequenceImpl<T> {

applyMixins(SequenceImpl, [AllOp, AnyOp, AsIterableOp, AssociateOp, AssociateByOp, AverageOp, ChunkOp, ContainsOp, CountOp, DistinctOp, DistinctByOp, DropOp, DropWhileOp,
ElementAtOp, ElementAtOrElseOp, ElementAtOrNullOp, FilterOp, FilterIndexedOp, FilterNotOp, FilterNotNullOp, FirstOp, FirstOrNullOp, FlatMapOp, FlattenOp, FoldOp,
FoldIndexedOp, ForEachOp, ForEachIndexedOp, GroupByOp, IndexOfOp, IndexOfFirstOp, IndexOfLastOp, JoinToStringOp, LastOp, LastOrNullOp, MapOp, MapIndexedOp, MapNotNullOp, MaxOp, MaxByOp,
FoldIndexedOp, ForEachOp, ForEachIndexedOp, GroupByOp, IndexOfOp, IndexOfFirstOp, IndexOfLastOp, IsEmptyOp, IsNotEmptyOp, JoinToStringOp, LastOp, LastOrNullOp, MapOp, MapIndexedOp, MapNotNullOp, MaxOp, MaxByOp,
MaxWithOp, MergeOp, MinOp, MinByOp, MinusOp, MinWithOp, NoneOp, OnEachOp, OnEachIndexedOp, PartitionOp, PlusOp, ReduceOp, ReduceIndexedOp, ReverseOp, SingleOp, SingleOrNullOp, SortedOp,
SortedByOp, SortedByDescendingOp, SortedDescendingOp, SortedWithOp, SumOp, SumByOp, TakeOp, TakeWhileOp, ToArrayOp, ToAsyncSequenceOp, ToMapOp, ToSetOp, UnzipOp, WithIndexOp, ZipOp]);
SortedByOp, SortedByDescendingOp, SortedDescendingOp, SortedWithOp, SumOp, SumByOp, TakeOp, TakeWhileOp, ToArrayOp, ToAsyncSequenceOp, ToMapOp, ToSetOp, UnzipOp, WithIndexOp, ZipOp]);
14 changes: 14 additions & 0 deletions src/operators/async/isEmpty.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {AsyncSequence} from "../../sequency";

export class IsEmpty {

/**
* Returns `true` the sequence is empty
*
* @returns {Promise<boolean>}
*/
async isEmpty<T>(this: AsyncSequence<T>): Promise<boolean> {
return !(await this.isNotEmpty());
}

}
14 changes: 14 additions & 0 deletions src/operators/async/isNotEmpty.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {AsyncSequence} from "../../sequency";

export class IsNotEmpty {

/**
* Returns `true` the sequence is not empty
*
* @returns {Promise<boolean>}
*/
async isNotEmpty<T>(this: AsyncSequence<T>): Promise<boolean> {
return await this.any(() => true);
}

}
14 changes: 14 additions & 0 deletions src/operators/sync/isEmpty.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {Sequence} from "../../sequency";

export class IsEmpty {

/**
* Returns `true` the sequence is empty
*
* @returns {boolean}
*/
isEmpty<T>(this: Sequence<T>): boolean {
return !this.isNotEmpty();
}

}
14 changes: 14 additions & 0 deletions src/operators/sync/isNotEmpty.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {Sequence} from "../../sequency";

export class IsNotEmpty {

/**
* Returns `true` the sequence is not empty
*
* @returns {boolean}
*/
isNotEmpty<T>(this: Sequence<T>): boolean {
return this.any(() => true);
}

}
39 changes: 39 additions & 0 deletions test/operators/async/isEmpty.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import {asyncSequenceOf, emptyAsyncSequence, asAsyncSequence} from "../../../src/sequency";

describe("isEmpty", () => {
it("returns false for infinite sequences", async () => {
const infiniteSequence = asAsyncSequence((async function* () {
let i = 0;
while (true) {
yield i++;
}
})());
const result = await infiniteSequence.isEmpty();
expect(result).toBeFalsy();
});

it("returns false for non-empty sequences", async () => {
const result = await asyncSequenceOf(1, 2, 3).isEmpty();
expect(result).toBeFalsy();
});

it("returns true for empty sequences", async () => {
const result = await emptyAsyncSequence().isEmpty();
expect(result).toBeTruthy();
});

it("returns true for sequences that would be empty", async () => {
const result = await asyncSequenceOf(1, 3)
.filter(async x => x % 2 === 0)
.isEmpty();
expect(result).toBeTruthy();
});

it("returns false for sequences that would not be empty", async () => {
const result = await asyncSequenceOf(1, 3)
.filter(async x => x % 2 !== 0)
.isEmpty();
expect(result).toBeFalsy();
});
});

39 changes: 39 additions & 0 deletions test/operators/async/isNotEmpty.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import {asyncSequenceOf, emptyAsyncSequence, asAsyncSequence} from "../../../src/sequency";

describe("isNotEmpty", () => {
it("returns true for infinite sequences", async () => {
const infiniteSequence = asAsyncSequence((async function* () {
let i = 0;
while (true) {
yield i++;
}
})());
const result = await infiniteSequence.isNotEmpty();
expect(result).toBeTruthy();
});

it("returns true for non-empty sequences", async () => {
const result = await asyncSequenceOf(1, 2, 3).isNotEmpty();
expect(result).toBeTruthy();
});

it("returns false for empty sequences", async () => {
const result = await emptyAsyncSequence().isNotEmpty();
expect(result).toBeFalsy();
});

it("returns false for sequences that would be empty", async () => {
const result = await asyncSequenceOf(1, 3)
.filter(async x => x % 2 === 0)
.isNotEmpty();
expect(result).toBeFalsy();
});

it("returns true for sequences that would not be empty", async () => {
const result = await asyncSequenceOf(1, 3)
.filter(async x => x % 2 !== 0)
.isNotEmpty();
expect(result).toBeTruthy();
});
});

20 changes: 20 additions & 0 deletions test/operators/sync/isEmpty.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {range, sequenceOf} from "../../../src/sequency";

describe("isEmpty", () => {
it("returns false for infinite sequences", () => {
expect(range(0, Infinity).isEmpty()).toBeFalsy();
});

it("returns true for empty sequences", () => {
expect(sequenceOf().isEmpty()).toBeTruthy();
});

it("returns true for sequences that would be empty", () => {
expect(sequenceOf(1, 3).filter(x => x % 2 === 0).isEmpty()).toBeTruthy();
});

it("returns false for sequences that would not be empty", () => {
expect(sequenceOf(1, 3).filter(x => x % 2 !== 0).isEmpty()).toBeFalsy();
});
});

20 changes: 20 additions & 0 deletions test/operators/sync/isNotEmpty.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {range, sequenceOf} from "../../../src/sequency";

describe("isNotEmpty", () => {
it("returns true for infinite sequences", () => {
expect(range(0, Infinity).isNotEmpty()).toBeTruthy();
});

it("returns false for empty sequences", () => {
expect(sequenceOf().isNotEmpty()).toBeFalsy();
});

it("returns false for sequences that would be empty", () => {
expect(sequenceOf(1, 3).filter(x => x % 2 === 0).isNotEmpty()).toBeFalsy();
});

it("returns true for sequences that would not be empty", () => {
expect(sequenceOf(1, 3).filter(x => x % 2 !== 0).isNotEmpty()).toBeTruthy();
});
});