Skip to content

Commit

Permalink
Refactor IQueryable and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
isc30 committed Sep 29, 2017
1 parent a647465 commit 4b0da2f
Show file tree
Hide file tree
Showing 13 changed files with 1,642 additions and 277 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "linq-collections",
"version": "1.0.46",
"version": "1.0.47",
"description": "Linq-Collections: (IEnumerable, ...) + (List, Dictionary, ...)",
"main": "./build/src/Linq.js",
"files": [
Expand Down Expand Up @@ -28,9 +28,9 @@
"homepage": "https://github.com/isc30/linq-collections#readme",
"scripts": {
"node-compile": "tsc",
"web-tests-compile": "browserify ./test/UnitTests.ts -p [tsify] > linq-tests.web.js",
"web-tests-compile": "browserify ./test/TestSuite.ts -p [tsify] > linq-tests.web.js",
"pretest": "npm run node-compile && npm run web-tests-compile",
"test": "nyc mocha ./build/test/UnitTests.js --slow 0",
"test": "nyc mocha ./build/test/TestSuite.js --slow 0",
"report-coverage": "nyc report --reporter=text-lcov | coveralls",
"publish-node": "npm run node-compile",
"publish-web": "browserify ./src/Linq.ts -p [tsify] > ./build/src/linq.web.js",
Expand Down
62 changes: 30 additions & 32 deletions src/Collections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { RangeEnumerable, OrderedEnumerable, IOrderedEnumerable, UniqueEnumerable, ConcatEnumerable, TransformEnumerable, ConditionalEnumerable, ReverseEnumerable, Enumerable, IEnumerable, ArrayEnumerable, IQueryable } from "./Enumerables";
import { Action, Selector, Aggregator, Predicate } from "./Types";
import { Comparer, createComparer } from "./Comparers";
import { IIterable } from "./Iterators";

interface IKeyValuePair<TKey, TValue>
{
Expand All @@ -16,9 +17,10 @@ interface IKeyValuePair<TKey, TValue>

export interface IList<TElement> extends IQueryable<TElement>
{
toEnumerable(): IEnumerable<TElement>;
asArray(): TElement[];
copy(): IList<TElement>;
copy(): List<TElement>;
// concat(other: IList<TElement>, ...others: Array<IList<TElement>>): IEnumerable<TElement>;
// except(other: IList<TElement>): IEnumerable<TElement>;
clear(): void;
at(index: number): TElement | undefined;
add(element: TElement): void;
Expand All @@ -35,7 +37,7 @@ export class List<TElement> implements IList<TElement>
this.source = elements;
}

public toEnumerable(): IEnumerable<TElement>
public asEnumerable(): IEnumerable<TElement>
{
return new ArrayEnumerable(this.source);
}
Expand All @@ -50,12 +52,12 @@ export class List<TElement> implements IList<TElement>
return ([] as TElement[]).concat(this.source);
}

public toList(): IList<TElement>
public toList(): List<TElement>
{
return this.copy();
}

public copy(): IList<TElement>
public copy(): List<TElement>
{
return new List<TElement>(this.toArray());
}
Expand Down Expand Up @@ -156,6 +158,14 @@ export class List<TElement> implements IList<TElement>
return this.source.length >>> 0;
}

public concat(
other: TElement[] | IQueryable<TElement>,
...others: Array<TElement[] | IQueryable<TElement>>)
: IEnumerable<TElement>
{
return this.asEnumerable().concat(other, ...others);
}

public elementAtOrDefault(index: number): TElement | undefined
{
if (index < 0)
Expand Down Expand Up @@ -196,7 +206,7 @@ export class List<TElement> implements IList<TElement>

public reverse(): IEnumerable<TElement>
{
return new ReverseEnumerable<TElement>(this.toEnumerable());
return new ReverseEnumerable<TElement>(this.asEnumerable());
}

public contains(element: TElement): boolean
Expand All @@ -206,44 +216,32 @@ export class List<TElement> implements IList<TElement>

public where(predicate: Predicate<TElement>): IEnumerable<TElement>
{
return new ConditionalEnumerable<TElement>(this.toEnumerable(), predicate);
return new ConditionalEnumerable<TElement>(this.asEnumerable(), predicate);
}

public select<TSelectorOut>(selector: Selector<TElement, TSelectorOut>): IEnumerable<TSelectorOut>
{
return new TransformEnumerable<TElement, TSelectorOut>(this.toEnumerable(), selector);
return new TransformEnumerable<TElement, TSelectorOut>(this.asEnumerable(), selector);
}

public selectMany<TSelectorOut>(
selector: Selector<TElement, TSelectorOut[] | IEnumerable<TSelectorOut>>)
selector: Selector<TElement, TSelectorOut[] | List<TSelectorOut> | IEnumerable<TSelectorOut>>)
: IEnumerable<TSelectorOut>
{
const selectToEnumerable = (e: TElement) =>
{
const ie = selector(e);

return Array.isArray(ie)
? Enumerable.fromSource(ie)
: ie;
? new ArrayEnumerable(ie)
: ie.asEnumerable();
};

return this
.select(selectToEnumerable).toArray()
.reduce((p, c) => new ConcatEnumerable(p, c), Enumerable.empty()) as IEnumerable<TSelectorOut>;
}

public concat(other: IEnumerable<TElement>, ...others: Array<IEnumerable<TElement>>): IEnumerable<TElement>
{
let result = new ConcatEnumerable<TElement>(this.toEnumerable(), other.copy());

for (let i = 0, end = others.length; i < end; ++i)
{
result = new ConcatEnumerable<TElement>(result, others[i].copy());
}

return result;
}

public elementAt(index: number): TElement
{
const element = this.elementAtOrDefault(index);
Expand Down Expand Up @@ -344,17 +342,17 @@ export class List<TElement> implements IList<TElement>
{
if (predicate !== undefined)
{
return this.toEnumerable().singleOrDefault(predicate);
return this.asEnumerable().singleOrDefault(predicate);
}

return this.toEnumerable().singleOrDefault();
return this.asEnumerable().singleOrDefault();
}

public distinct(): IEnumerable<TElement>;
public distinct<TKey>(keySelector: Selector<TElement, TKey>): IEnumerable<TElement>;
public distinct<TKey>(keySelector?: Selector<TElement, TKey>): IEnumerable<TElement>
{
return new UniqueEnumerable(this.toEnumerable(), keySelector);
return new UniqueEnumerable(this.asEnumerable(), keySelector);
}

public min(): TElement;
Expand All @@ -364,7 +362,7 @@ export class List<TElement> implements IList<TElement>
if (selector !== undefined)
{
// Don't copy iterators
return new TransformEnumerable<TElement, TSelectorOut>(this.toEnumerable(), selector).min();
return new TransformEnumerable<TElement, TSelectorOut>(this.asEnumerable(), selector).min();
}

return this.aggregate((previous, current) =>
Expand All @@ -382,13 +380,13 @@ export class List<TElement> implements IList<TElement>
keySelector: Selector<TElement, TKey>,
comparer?: Comparer<TKey>): IOrderedEnumerable<TElement>
{
return new OrderedEnumerable(this.toEnumerable(), createComparer(keySelector, true, comparer));
return new OrderedEnumerable(this.asEnumerable(), createComparer(keySelector, true, comparer));
}

public orderByDescending<TKey>(
keySelector: Selector<TElement, TKey>): IOrderedEnumerable<TElement>
{
return new OrderedEnumerable(this.toEnumerable(), createComparer(keySelector, false, undefined));
return new OrderedEnumerable(this.asEnumerable(), createComparer(keySelector, false, undefined));
}

public max(): TElement;
Expand All @@ -398,7 +396,7 @@ export class List<TElement> implements IList<TElement>
if (selector !== undefined)
{
// Don't copy iterators
return new TransformEnumerable<TElement, TSelectorOut>(this.toEnumerable(), selector).max();
return new TransformEnumerable<TElement, TSelectorOut>(this.asEnumerable(), selector).max();
}

return this.aggregate((previous, current) =>
Expand All @@ -415,12 +413,12 @@ export class List<TElement> implements IList<TElement>

public skip(amount: number): IEnumerable<TElement>
{
return new RangeEnumerable<TElement>(this.toEnumerable(), amount, undefined);
return new RangeEnumerable<TElement>(this.asEnumerable(), amount, undefined);
}

public take(amount: number): IEnumerable<TElement>
{
return new RangeEnumerable<TElement>(this.toEnumerable(), undefined, amount);
return new RangeEnumerable<TElement>(this.asEnumerable(), undefined, amount);
}

public union(other: IEnumerable<TElement>): IEnumerable<TElement>
Expand Down
47 changes: 34 additions & 13 deletions src/Enumerables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/

import { Selector, Predicate, Aggregator, Action, Dynamic, Primitive } from "./Types";
import { IList, List } from "./Collections";
import { List } from "./Collections";
import { IIterable, ArrayIterator } from "./Iterators";
import { Comparer, createComparer, combineComparers } from "./Comparers";
import { Cached } from "./Utils";
Expand All @@ -13,8 +13,9 @@ export interface IQueryable<TOut>
{
copy(): IQueryable<TOut>;

asEnumerable(): IEnumerable<TOut>;
toArray(): TOut[];
toList(): IList<TOut>;
toList(): List<TOut>;
// toDictionary
// toLookup

Expand All @@ -28,7 +29,10 @@ export interface IQueryable<TOut>

average(selector: Selector<TOut, number>): number;

concat(other: IEnumerable<TOut>, ...others: Array<IEnumerable<TOut>>): IEnumerable<TOut>;
concat(
other: TOut[] | IQueryable<TOut>,
...others: Array<TOut[] | IQueryable<TOut>>)
: IEnumerable<TOut>;

contains(element: TOut): boolean;

Expand All @@ -44,7 +48,7 @@ export interface IQueryable<TOut>

elementAtOrDefault(index: number): TOut | undefined;

except(other: IEnumerable<TOut>): IEnumerable<TOut>;
// +++ except

first(): TOut;
first(predicate: Predicate<TOut>): TOut;
Expand Down Expand Up @@ -90,7 +94,7 @@ export interface IQueryable<TOut>
select<TSelectorOut>(selector: Selector<TOut, TSelectorOut>): IEnumerable<TSelectorOut>;

selectMany<TSelectorOut>(
selector: Selector<TOut, TSelectorOut[] | IEnumerable<TSelectorOut>>)
selector: Selector<TOut, TSelectorOut[] | IQueryable<TSelectorOut>>)
: IEnumerable<TSelectorOut>;

// sequenceEqual
Expand All @@ -117,6 +121,8 @@ export interface IQueryable<TOut>
export interface IEnumerable<TOut> extends IQueryable<TOut>, IIterable<TOut>
{
copy(): IEnumerable<TOut>;

except(other: IEnumerable<TOut>): IEnumerable<TOut>;
}

export interface IOrderedEnumerable<TOut> extends IEnumerable<TOut>
Expand Down Expand Up @@ -154,6 +160,11 @@ export abstract class EnumerableBase<TElement, TOut> implements IEnumerable<TOut
return this.source.next();
}

public asEnumerable(): IEnumerable<TOut>
{
return this;
}

public toArray(): TOut[]
{
const result: TOut[] = [];
Expand All @@ -167,7 +178,7 @@ export abstract class EnumerableBase<TElement, TOut> implements IEnumerable<TOut
return result;
}

public toList(): IList<TOut>
public toList(): List<TOut>
{
return new List<TOut>(this.toArray());
}
Expand Down Expand Up @@ -245,30 +256,40 @@ export abstract class EnumerableBase<TElement, TOut> implements IEnumerable<TOut
}

public selectMany<TSelectorOut>(
selector: Selector<TOut, TSelectorOut[] | IEnumerable<TSelectorOut>>)
selector: Selector<TOut, TSelectorOut[] | IQueryable<TSelectorOut>>)
: IEnumerable<TSelectorOut>
{
const selectToEnumerable = (e: TOut) =>
{
const ie = selector(e);

return Array.isArray(ie)
? Enumerable.fromSource(ie)
: ie;
? new ArrayEnumerable(ie)
: ie.asEnumerable();
};

return this
.select(selectToEnumerable).toArray()
.reduce((p, c) => new ConcatEnumerable(p, c), Enumerable.empty()) as IEnumerable<TSelectorOut>;
}

public concat(other: IEnumerable<TOut>, ...others: Array<IEnumerable<TOut>>): IEnumerable<TOut>
public concat(
other: TOut[] | IQueryable<TOut>,
...others: Array<TOut[] | IQueryable<TOut>>)
: IEnumerable<TOut>
{
let result = new ConcatEnumerable<TOut>(this.copy(), other.copy());
const asEnumerable = (e: TOut[] | IQueryable<TOut>): IIterable<TOut> =>
{
return Array.isArray(e)
? new ArrayEnumerable(e)
: e.asEnumerable();
};

let result = new ConcatEnumerable<TOut>(this.copy(), asEnumerable(other).copy());

for (let i = 0, end = others.length; i < end; ++i)
{
result = new ConcatEnumerable<TOut>(result, others[i].copy());
result = new ConcatEnumerable<TOut>(result, asEnumerable(others[i]).copy());
}

return result;
Expand Down Expand Up @@ -1170,7 +1191,7 @@ export class OrderedEnumerable<TElement>

export class ArrayEnumerable<TOut> extends Enumerable<TOut>
{
protected _list: IList<TOut>;
protected _list: List<TOut>;

public constructor(source: TOut[])
{
Expand Down

0 comments on commit 4b0da2f

Please sign in to comment.