Skip to content

Commit

Permalink
Merge branch 'master' into 25-create-aggregate-operation
Browse files Browse the repository at this point in the history
  • Loading branch information
Farenheith authored Jul 2, 2023
2 parents 2383a06 + ddcf160 commit a5a5e48
Show file tree
Hide file tree
Showing 24 changed files with 397 additions and 49 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
# [1.31.0](https://github.com/codibre/fluent-iterable/compare/v1.30.0...v1.31.0) (2023-06-30)


### Features

* implementing distinctby ([#67](https://github.com/codibre/fluent-iterable/issues/67)) ([a75ce0c](https://github.com/codibre/fluent-iterable/commit/a75ce0c64ca2f38e38105d368594e430a14adab0))

# [1.30.0](https://github.com/codibre/fluent-iterable/compare/v1.29.2...v1.30.0) (2023-04-26)


### Features

* accepting function mapping for to object chain ([#65](https://github.com/codibre/fluent-iterable/issues/65)) ([14d1632](https://github.com/codibre/fluent-iterable/commit/14d163229fc30e5f8125b2f224c55f9b4aff6955))

## [1.29.2](https://github.com/codibre/fluent-iterable/compare/v1.29.1...v1.29.2) (2023-04-04)


Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@codibre/fluent-iterable",
"description": "Provides LINQ-like fluent api operations for iterables and async iterables (ES2018+).",
"version": "1.29.2",
"version": "1.31.0",
"private": false,
"author": {
"name": "Thiago O Santos <[email protected]>"
Expand Down
19 changes: 19 additions & 0 deletions src/async/distinct-by-async.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { distinctByRecipe } from '../recipes';
import { filterAsync } from './filter-async';
import { hasLessOrExactlyAsync } from './has-less-or-exactly-async';
import { basicAsync } from './basic-ingredients-async';
import { partitionAsync } from './partition-async';
import { Ingredient, ResolverIngredient } from '../recipes/ingredients';
import { reduceAsync } from './reduce-async';

function distinctAsyncRecipe(filterOrAll: Ingredient | ResolverIngredient) {
return distinctByRecipe({
...basicAsync,
partition: partitionAsync,
filterOrAll,
hasLessOrExactly: hasLessOrExactlyAsync,
reduce: reduceAsync,
});
}

export const distinctByAsync = distinctAsyncRecipe(filterAsync);
1 change: 1 addition & 0 deletions src/async/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export * from './concat-async';
export * from './contains-async';
export * from './count-async';
export * from './distinct-async';
export * from './distinct-by-async';
export * from './emit-async';
export * from './execute-async';
export * from './filter-async';
Expand Down
4 changes: 2 additions & 2 deletions src/async/to-object-chain-async.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { toObjectChainRecipe } from '../recipes';
import { basicAsync } from './basic-ingredients-async';
import { flattenAsync } from './flatten-async';
import { groupAsync } from './group-async';
import { reduceAsync } from './reduce-async';
import { toObjectAsync } from './to-object-async';
import { unwindAsync } from './unwind-async';

export const toObjectChainAsync = toObjectChainRecipe({
...basicAsync,
group: groupAsync,
toObject: toObjectAsync,
unwind: unwindAsync,
flatten: flattenAsync,
reduce: reduceAsync,
});
4 changes: 2 additions & 2 deletions src/async/to-object-chain-reduce-async.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { toObjectChainReduceRecipe } from '../recipes';
import { basicAsync } from './basic-ingredients-async';
import { flattenAsync } from './flatten-async';
import { groupAsync } from './group-async';
import { reduceAsync } from './reduce-async';
import { toObjectAsync } from './to-object-async';
import { unwindAsync } from './unwind-async';

export const toObjectChainReduceAsync = toObjectChainReduceRecipe({
...basicAsync,
group: groupAsync,
toObject: toObjectAsync,
unwind: unwindAsync,
flatten: flattenAsync,
reduce: reduceAsync,
});
2 changes: 2 additions & 0 deletions src/mounters/fluent-async-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import {
unwindAsync,
finallyAsync,
toObjectChainReduceAsync,
distinctByAsync,
} from '../async';
import {
combineEmitter,
Expand Down Expand Up @@ -93,6 +94,7 @@ export const asyncIterableFuncs = {
sort: sortAsync,
sortBy: sortByAsync,
distinct: distinctAsync,
distinctBy: distinctByAsync,
distinctAsync,
execute: executeAsync,
merge,
Expand Down
4 changes: 4 additions & 0 deletions src/mounters/fluent-functions.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { distinctByAsync } from './../async/distinct-by-async';
import {
aggregate,
any,
Expand Down Expand Up @@ -32,6 +33,7 @@ import {
sort,
sortBy,
distinct,
distinctBy,
group,
last,
all,
Expand Down Expand Up @@ -118,6 +120,7 @@ export const iterableFuncs = {
sort,
sortBy,
distinct,
distinctBy,
execute,
combine,
combineJoin,
Expand All @@ -138,6 +141,7 @@ export const iterableAsyncFuncs = {
flatMerge,
flatMapAsync: flattenAsync,
distinctAsync,
distinctByAsync,
executeAsync,
toAsync,
combineAsync,
Expand Down
51 changes: 51 additions & 0 deletions src/recipes/distinct-by-recipe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { AnyIterable } from 'augmentative-iterable';
import { AnyMapper, FunctionAnyMapper } from '../types-internal';
import { DistinctIngredients } from './ingredients';
import { prepare } from '../types-internal/prepare';

function chooseDistinctByRecipe({ forEach, resolver }: DistinctIngredients) {
return function distinct<T>(
this: AnyIterable<T>,
mappers: FunctionAnyMapper<any>[],
) {
const { length } = mappers;
const setPos = length - 1;
const lastMap = setPos - 1;
const map = setPos === 0 ? new Set() : new Map();
const result: any[] = [];

return resolver(
forEach.call(this, (x) => {
let current: any = map;
for (let i = 0; i < setPos; i++) {
const mapper = mappers[i];
const k = mapper(x);
const prev = current;
current = prev.get(k);
if (!current) {
current = i === lastMap ? new Set() : new Map();
prev.set(k, current);
}
}
const k = mappers[setPos](x);
if (!current.has(k)) {
current.add(k);
result.push(x);
}
}),
() => result,
);
};
}

export function distinctByRecipe(ingredients: DistinctIngredients) {
const choose = chooseDistinctByRecipe(ingredients);

return function distinctBy<T>(
this: AnyIterable<T>,
...baseMappers: Array<AnyMapper<T>>
) {
const mappers = baseMappers.map(prepare);
return choose.call(this, mappers);
};
}
1 change: 1 addition & 0 deletions src/recipes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export * from './comparison-recipe';
export * from './concat-recipe';
export * from './contains-recipe';
export * from './count-recipe';
export * from './distinct-by-recipe';
export * from './distinct-recipe';
export * from './emit-recipe';
export * from './execute-recipe';
Expand Down
2 changes: 1 addition & 1 deletion src/recipes/ingredients.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,6 @@ export interface UnwindIngredients extends BasicIngredients {
export interface ToObjectChainIngredients extends BasicIngredients {
group: Function;
toObject: Function;
unwind: Function;
flatten: Function;
reduce: AsyncReducer<any, any>;
}
45 changes: 27 additions & 18 deletions src/recipes/to-object-chain-reduce-recipe.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,45 @@
import { FunctionAnyMapper } from './../types/any-mapper';
import { AnyIterable } from 'augmentative-iterable';
import { AsyncReducer } from '../types';
import { ToObjectChainIngredients } from './ingredients';
import { prepare } from '../types-internal/prepare';

function unwindAndGroup(
it: AnyIterable<any>,
ing: ToObjectChainIngredients,
key: FunctionAnyMapper<any>,
) {
it = ing.flatten.call(it, (x: any) => {
const current = key(x);
return typeof current !== 'string' &&
typeof current[Symbol.iterator] === 'function'
? ing.map.call(current, (item) => [item, x])
: [[current, x]];
});
return ing.group.call(
it,
(x: any) => x[0],
(_k: any, v: any) => [v[1]],
);
}

function toObjectNode<T, R>(
it: AnyIterable<any>,
keys: string[],
keys: FunctionAnyMapper<any>[],
index: number,
ing: ToObjectChainIngredients,
reducer: AsyncReducer<T, R>,
initial: () => R,
): any {
const key = keys[index];
it = ing.unwind.call(it, key);
it = ing.group.call(it, (x: any) => x.unwinded[key]);
it = unwindAndGroup(it, ing, key);
return ing.toObject.call(
it,
'key',
index < keys.length - 1
? (subIt: any) =>
toObjectNode(
ing.map.call(subIt.values, (x: any) => x.value),
keys,
index + 1,
ing,
reducer,
initial,
)
: (subIt: any) =>
ing.reduce.call(
ing.map.call(subIt.values, (x: any) => x.value),
reducer,
initial(),
),
toObjectNode(subIt.values, keys, index + 1, ing, reducer, initial)
: (subIt: any) => ing.reduce.call(subIt.values, reducer, initial()),
);
}

Expand All @@ -42,8 +50,9 @@ export function toObjectChainReduceRecipe(ing: ToObjectChainIngredients) {
reducer: AsyncReducer<T, R>,
...keys: string[]
) {
const prepared = keys.map((x) => prepare(x));
return keys.length === 0
? ing.reduce.call(this, reducer, initial())
: toObjectNode(this, keys, 0, ing, reducer, initial);
: toObjectNode(this, prepared, 0, ing, reducer, initial);
};
}
19 changes: 19 additions & 0 deletions src/sync/distinct-by.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { basic } from './basic-ingredients';
import { distinctByRecipe } from '../recipes';
import { filter } from './filter';
import { hasLessOrExactly } from './has-less-or-exactly';
import { partition } from './partition';
import { reduce } from './reduce';
import { Ingredient, ResolverIngredient } from '../recipes/ingredients';

function distinctSyncRecipe(filterOrAll: Ingredient | ResolverIngredient) {
return distinctByRecipe({
...basic,
partition,
filterOrAll,
hasLessOrExactly,
reduce,
});
}

export const distinctBy = distinctSyncRecipe(filter);
1 change: 1 addition & 0 deletions src/sync/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export * from './concat';
export * from './contains';
export * from './count';
export * from './distinct';
export * from './distinct-by';
export * from './emit';
export * from './execute';
export * from './filter';
Expand Down
4 changes: 2 additions & 2 deletions src/sync/to-object-chain-reduce.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { toObjectChainReduceRecipe } from '../recipes';
import { basic } from './basic-ingredients';
import { flatten } from './flatten';
import { group } from './group';
import { reduce } from './reduce';
import { toObject } from './to-object';
import { unwind } from './unwind';

export const toObjectChainReduce = toObjectChainReduceRecipe({
...basic,
group,
toObject,
unwind,
flatten,
reduce,
});
4 changes: 2 additions & 2 deletions src/sync/to-object-chain.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { toObjectChainRecipe } from '../recipes';
import { basic } from './basic-ingredients';
import { flatten } from './flatten';
import { group } from './group';
import { reduce } from './reduce';
import { toObject } from './to-object';
import { unwind } from './unwind';

export const toObjectChain = toObjectChainRecipe({
...basic,
group,
toObject,
unwind,
flatten,
reduce,
});
1 change: 1 addition & 0 deletions src/types/fluent-async-iterable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ declare module './base' {
sort: f.AsyncSortFunction<T>;
sortBy: f.AsyncSortByFunction<T>;
distinct: f.AsyncDistinctFunction<T>;
distinctBy: f.AsyncDistinctByFunction<T>;
isDistinct: f.AsyncIsDistinctFunction<T>;
group: f.AsyncGroupFunction<T>;
count: f.AsyncCountFunction<T>;
Expand Down
2 changes: 2 additions & 0 deletions src/types/fluent-iterable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ declare module './base' {
sort: f.SortFunction<T>;
sortBy: f.SortByFunction<T>;
distinct: f.DistinctFunction<T>;
distinctBy: f.DistinctByFunction<T>;
distinctByAsync: f.AsyncDistinctByFunction<T>;
distinctAsync: f.AsyncDistinctFunction<T>;
isDistinct: f.IsDistinctFunction<T>;
isDistinctAsync: f.AsyncIsDistinctFunction<T>;
Expand Down
25 changes: 25 additions & 0 deletions src/types/function-types/distinct-by-function.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { AsyncMapper, Mapper } from 'augmentative-iterable';
import { FluentAsyncIterable, FluentIterable } from '../base';

export interface DistinctByFunction<T> {
/**
* Returns distinct elements from the iterable from a certain list of projections<br>
* Examples:<br>
* * `fluent([{ a: 1, b: 2, c: 1}, { a: 1, b: 2, c: 2}]).distinct()` yields *{ a: 1, b: 2, c: 1 }*<br>
* @typeparam R The type of the data the element equality is based on.
* @param mappers The projections to use to determine element equality.
* @returns The [[FluentIterable]] of the distinct elements.
*/
<R>(...mappers: Array<Mapper<T, R> | keyof T>): FluentIterable<T>;
}
export interface AsyncDistinctByFunction<T> {
/**
* Returns distinct elements from the iterable from a certain list of projections<br>
* Examples:<br>
* * `fluent([{ a: 1, b: 2, c: 1}, { a: 1, b: 2, c: 2}]).distinct()` yields *{ a: 1, b: 2, c: 1 }*<br>
* @typeparam R The type of the data the element equality is based on.
* @param mappers The projections to use to determine element equality.
* @returns The [[FluentIterable]] of the distinct elements.
*/
<R>(...mappers: Array<AsyncMapper<T, R> | keyof T>): FluentAsyncIterable<T>;
}
1 change: 1 addition & 0 deletions src/types/function-types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export * from './combine-join-function';
export * from './concat-function';
export * from './contains-function';
export * from './count-function';
export * from './distinct-by-function';
export * from './distinct-function';
export * from './emit-function';
export * from './execute-function';
Expand Down
Loading

0 comments on commit a5a5e48

Please sign in to comment.