Skip to content

Commit

Permalink
fix: fixing flatMap fields mapping for one field flatting (#62)
Browse files Browse the repository at this point in the history
  • Loading branch information
Farenheith authored Apr 4, 2023
1 parent a118469 commit e50818c
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 142 deletions.
81 changes: 52 additions & 29 deletions 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
Expand Up @@ -129,7 +129,7 @@
"sinon": "^11.1.2",
"sinon-chai": "^3.7.0",
"stream-mock": "^2.0.5",
"ts-node": "^10.4.0",
"ts-node": "^10.9.1",
"tsconfig-paths": "^3.11.0",
"typedoc": "^0.22.17",
"typedoc-plugin-markdown": "^3.11.3",
Expand Down
152 changes: 43 additions & 109 deletions src/recipes/flat-join-recipe.ts
Original file line number Diff line number Diff line change
@@ -1,130 +1,64 @@
import { tail, head } from './../types/base';
import { isIterable } from '../is-iterable';
import { CombineIngredients, Ingredient } from './ingredients';
import { AnyIterable } from 'augmentative-iterable';
import { CombineIngredients } from './ingredients';

function flattable(value: unknown) {
return typeof value !== 'string' && isIterable(value);
}

function getNextIterable(
current: any,
path: string[],
nextIndex: number,
): [any, number] {
let item = current;
if (flattable(item)) {
return [item, nextIndex];
function fillField(result: any, field: string, subItem: any) {
if (!result.hasOwnProperty(field)) {
result[field] = subItem;
}

while (nextIndex < path.length) {
item = item[path[nextIndex]];
nextIndex++;
if (flattable(item)) {
break;
}
}
return [item, nextIndex];
}

function fillMiddleFieldsFactory(
oldItem: any,
start: number,
nextIndex: number,
path: string[],
) {
return (x: any) => {
let current = oldItem;
for (let i = start; i < nextIndex; i++) {
current = current[path[i]];
if (!flattable(current)) {
x[path[i]] = current;
}
}

return x;
};
}

function fillMiddleToHeadFieldsFactory(
oldItem: any,
start: number,
nextIndex: number,
path: string[],
) {
const fillMiddleFields = fillMiddleFieldsFactory(
oldItem,
start,
nextIndex,
path,
);
return (sub: any) => {
const newItem = fillMiddleFields({});
newItem[head] = sub;
return newItem;
function getNewResult(result: any, field: string, subItem: any): any {
result = {
...result,
};
fillField(result, field, subItem);
return result;
}

function mapRoot(
iterable: AnyIterable<any>,
map: Ingredient,
key: string | number | symbol,
value: unknown,
) {
return map.call(iterable, (x) => {
x[key] = value;
return x;
});
}

function flatMap(
item: any,
ingredients: CombineIngredients,
path: string[],
nextIndex: number,
): any {
const oldItem = item;
const { flatten, map } = ingredients;
const start = nextIndex;
const result = getNextIterable(item, path, nextIndex);
item = result[0];
nextIndex = result[1];
function flatMapFactory(ingredients: CombineIngredients, deepFlat: Function) {
return function flatMap(
result: any,
item: any,
path: string[],
nextIndex: number,
): any {
const { flatten } = ingredients;
const start = nextIndex;

if (nextIndex < path.length) {
return flatten.call(item, (sub: any) => {
const mapped = map.call(
flatMap(sub, ingredients, path, nextIndex),
fillMiddleFieldsFactory(oldItem, start, nextIndex, path),
);
return mapRoot(
mapped,
map,
nextIndex > 0 ? path[nextIndex - 1] : tail,
sub,
);
});
}

const fillMiddleToHeadItems = fillMiddleToHeadFieldsFactory(
oldItem,
start,
nextIndex,
path,
);
let current: any = item;
for (let i = start; i < path.length; i++) {
const field = path[i];
current = current[field];
if (flattable(current)) {
return flatten.call(deepFlat(current), (subItem: any) =>
flatMap(getNewResult(result, field, subItem), subItem, path, i + 1),
);
}
fillField(result, field, current);
}
result[head] = current;

return flattable(item)
? map.call(item, fillMiddleToHeadItems)
: [fillMiddleToHeadItems(item)];
return [result];
};
}

export function flatJoinRecipe(ingredients: CombineIngredients) {
const { map, iterateAll } = ingredients;
const { flatten } = ingredients;
const deepFlat = (x: Iterable<any>): any =>
flatten.call(x, (y: any) => (flattable(y) ? deepFlat(y) : [y]));
const flatMap = flatMapFactory(ingredients, deepFlat);
return function <T, R>(this: Iterable<T>, ...path: string[]): Iterable<R> {
return iterateAll(
map.call(this, (x) => {
const flatted = flatMap(x, ingredients, path, 0);
return flattable(x) ? flatted : mapRoot(flatted, map, tail, x);
}),
);
function process(y: any): any {
return flatMap({ [tail]: y }, y, path, 0);
}

return flatten.call(this, (x) =>
flattable(x) ? flatten.call(deepFlat(x), process) : process(x),
) as any;
};
}
Loading

0 comments on commit e50818c

Please sign in to comment.