diff --git a/.eslintignore b/.eslintignore index ec1d562b..d14a159c 100644 --- a/.eslintignore +++ b/.eslintignore @@ -433,4 +433,7 @@ app/javascript/legacy_react/src/components/registration_page/UserInfoForm.tsx app/javascript/legacy_react/src/components/registration_page/UserInfoPanel.spec.tsx app/javascript/legacy_react/src/components/registration_page/UserInfoPanel.tsx app/javascript/legacy_react/src/components/session_login_page/SessionLoginForm.tsx -app/javascript/legacy_react/src/components/session_login_page/SessionLoginPage.tsx \ No newline at end of file +app/javascript/legacy_react/src/components/session_login_page/SessionLoginPage.tsx + +#included code from another package +app/javascript/common/lodash-joins \ No newline at end of file diff --git a/NOTICE-js b/NOTICE-js index 0c54123d..b5392af3 100644 --- a/NOTICE-js +++ b/NOTICE-js @@ -1603,6 +1603,8 @@ END OF TERMS AND CONDITIONS ------ +** lodash-joins; version 3.0.1 -- https://github.com/mtraynham/lodash-joins#readme +Copyright (c) Microsoft Corporation. ** reduce-component; version 1.0.1 -- Copyright 2012 Red Ventures ** xml-name-validator; version 3.0.0 -- https://github.com/jsdom/xml-name-validator#readme diff --git a/app/javascript/common/lodash-joins/hash/hashFullOuterJoin.ts b/app/javascript/common/lodash-joins/hash/hashFullOuterJoin.ts new file mode 100644 index 00000000..93b59736 --- /dev/null +++ b/app/javascript/common/lodash-joins/hash/hashFullOuterJoin.ts @@ -0,0 +1,72 @@ +// License: LGPL-3.0-or-later +// from https://github.com/mtraynham/lodash-joins/blob/c252b462981562451d85d1e09c8f273ce7fe06c5/lib/hash/hashFullOuterJoin.ts +import filter from 'lodash/filter'; +import flatten from 'lodash/flatten'; +import groupBy from 'lodash/groupBy'; +import has from 'lodash/has'; +import map from 'lodash/map'; +import reduceRight from 'lodash/reduceRight'; +import values from 'lodash/values'; + +import {Accessor, Merger} from '../typings'; +import {toStringAccessor} from './util'; + +/** + * Hash full outer join + */ +export default function hashFullOuterJoin( + a: LeftRow[], + aAccessor: Accessor, + b: RightRow[], + bAccessor: Accessor, + merger: Merger +): MergeResult[] { + if (a.length < 1 || b.length < 1) { + return [ + ...a.map((a: LeftRow) => merger(a, undefined)), + ...b.map((b: RightRow) => merger(undefined, b)) + ]; + } + const leftAccessor: Accessor = toStringAccessor(aAccessor), + rightAccessor: Accessor = toStringAccessor(bAccessor), + seen: {[key: string]: boolean} = {}; + let index: {[key: string]: (LeftRow | RightRow)[]}, + result: MergeResult[], + key: string; + if (a.length < b.length) { + index = groupBy(a, leftAccessor); + result = reduceRight(b, (previous: MergeResult[], bDatum: RightRow) => { + seen[key = rightAccessor(bDatum)] = true; + if (has(index, key)) { + return map(index[key], (aDatum: LeftRow) => merger(aDatum, bDatum)).concat(previous); + } + previous.unshift(merger(undefined, bDatum)); + return previous; + }, []); + return result.concat( + map( + flatten(values(filter( + index, + (val: (LeftRow | RightRow)[], key: string) => + !has(seen, key)))), + (aDatum: LeftRow) => + merger(aDatum, undefined))); + } + index = groupBy(b, rightAccessor); + result = reduceRight(a, (previous: MergeResult[], aDatum: LeftRow) => { + seen[key = leftAccessor(aDatum)] = true; + if (has(index, key)) { + return map(index[key], (bDatum: RightRow) => merger(aDatum, bDatum)).concat(previous); + } + previous.unshift(merger(aDatum, undefined)); + return previous; + }, []); + return result.concat( + map( + flatten(values(filter( + index, + (val: (LeftRow | RightRow)[], key: string) => + !has(seen, key)))), + (bDatum: RightRow) => + merger(undefined, bDatum))); +} diff --git a/app/javascript/common/lodash-joins/hash/hashInnerJoin.ts b/app/javascript/common/lodash-joins/hash/hashInnerJoin.ts new file mode 100644 index 00000000..a9556d74 --- /dev/null +++ b/app/javascript/common/lodash-joins/hash/hashInnerJoin.ts @@ -0,0 +1,46 @@ +// License: LGPL-3.0-or-later +// from https://github.com/mtraynham/lodash-joins/blob/c252b462981562451d85d1e09c8f273ce7fe06c5/lib/hash/hashInnerJoin.ts +import groupBy from 'lodash/groupBy'; +import has from 'lodash/has'; +import map from 'lodash/map'; +import reduceRight from 'lodash/reduceRight'; + +import {Accessor, Merger} from '../typings'; +import {toStringAccessor} from './util'; + +/** + * Hash inner join + */ +export default function hashInnerJoin( + a: LeftRow[], + aAccessor: Accessor, + b: RightRow[], + bAccessor: Accessor, + merger: Merger +): MergeResult[] { + if (a.length < 1 || b.length < 1) { + return []; + } + const leftAccessor: Accessor = toStringAccessor(aAccessor), + rightAccessor: Accessor = toStringAccessor(bAccessor); + let index: {[key: string]: (LeftRow | RightRow)[]}, + key: string; + if (a.length < b.length) { + index = groupBy(a, leftAccessor); + return reduceRight(b, (previous: MergeResult[], bDatum: RightRow) => { + key = rightAccessor(bDatum); + if (has(index, key)) { + return map(index[key], (aDatum: LeftRow) => merger(aDatum, bDatum)).concat(previous); + } + return previous; + }, []); + } + index = groupBy(b, rightAccessor); + return reduceRight(a, (previous: MergeResult[], aDatum: LeftRow) => { + key = leftAccessor(aDatum); + if (has(index, key)) { + return map(index[key], (bDatum: RightRow) => merger(aDatum, bDatum)).concat(previous); + } + return previous; + }, []); +} diff --git a/app/javascript/common/lodash-joins/hash/hashLeftAntiJoin.ts b/app/javascript/common/lodash-joins/hash/hashLeftAntiJoin.ts new file mode 100644 index 00000000..fe3acd4f --- /dev/null +++ b/app/javascript/common/lodash-joins/hash/hashLeftAntiJoin.ts @@ -0,0 +1,25 @@ +// License: LGPL-3.0-or-later +// from https://github.com/mtraynham/lodash-joins/blob/c252b462981562451d85d1e09c8f273ce7fe06c5/lib/hash/hashLeftAntiJoin.ts +import filter from 'lodash/filter'; +import has from 'lodash/has'; +import keyBy from 'lodash/keyBy'; + +import {Accessor} from '../typings'; +import {toStringAccessor} from './util'; + +/** + * Hash left anti join + */ +export default function hashLeftAntiJoin( + a: LeftRow[], + aAccessor: Accessor, + b: RightRow[], + bAccessor: Accessor +): LeftRow[] { + if (a.length < 1 || b.length < 1) { + return a; + } + const index: {[key: string]: RightRow} = keyBy(b, toStringAccessor(bAccessor)), + leftAccessor: Accessor = toStringAccessor(aAccessor); + return filter(a, (aDatum: LeftRow) => !has(index, leftAccessor(aDatum))); +} diff --git a/app/javascript/common/lodash-joins/hash/hashLeftOuterJoin.ts b/app/javascript/common/lodash-joins/hash/hashLeftOuterJoin.ts new file mode 100644 index 00000000..b0384b3d --- /dev/null +++ b/app/javascript/common/lodash-joins/hash/hashLeftOuterJoin.ts @@ -0,0 +1,57 @@ +// License: LGPL-3.0-or-later +// from https://github.com/mtraynham/lodash-joins/blob/c252b462981562451d85d1e09c8f273ce7fe06c5/lib/hash/hashLeftOuterJoin.ts +import filter from 'lodash/filter'; +import flatten from 'lodash/flatten'; +import groupBy from 'lodash/groupBy'; +import has from 'lodash/has'; +import map from 'lodash/map'; +import reduceRight from 'lodash/reduceRight'; +import values from 'lodash/values'; + +import {Accessor, Merger} from '../typings'; +import {toStringAccessor} from './util'; + +/** + * Hash left outer join + */ +export default function hashLeftOuterJoin( + a: LeftRow[], + aAccessor: Accessor, + b: RightRow[], + bAccessor: Accessor, + merger: Merger +): MergeResult[] { + if (a.length < 1 || b.length < 1) { + return map(a, (a: LeftRow) => merger(a, undefined)); + } + const leftAccessor: Accessor = toStringAccessor(aAccessor), + rightAccessor: Accessor = toStringAccessor(bAccessor); + let index: {[key: string]: (LeftRow | RightRow)[]}, + key: string; + if (a.length < b.length) { + const seen: {[key: string]: boolean} = {}; + index = groupBy(a, leftAccessor); + return reduceRight(b, (previous: MergeResult[], bDatum: RightRow) => { + seen[key = rightAccessor(bDatum)] = true; + if (has(index, key)) { + return map(index[key], (aDatum: LeftRow) => merger(aDatum, bDatum)).concat(previous); + } + return previous; + }, []).concat( + map( + flatten(values(filter( + index, + (val: (LeftRow | RightRow)[], key: string) => + !has(seen, key)))), + (aDatum: LeftRow) => merger(aDatum, undefined))); + } + index = groupBy(b, rightAccessor); + return reduceRight(a, (previous: MergeResult[], aDatum: LeftRow) => { + key = leftAccessor(aDatum); + if (has(index, key)) { + return map(index[key], (bDatum: RightRow) => merger(aDatum, bDatum)).concat(previous); + } + previous.unshift(merger(aDatum, undefined)); + return previous; + }, []); +} diff --git a/app/javascript/common/lodash-joins/hash/hashLeftSemiJoin.ts b/app/javascript/common/lodash-joins/hash/hashLeftSemiJoin.ts new file mode 100644 index 00000000..6be43fd2 --- /dev/null +++ b/app/javascript/common/lodash-joins/hash/hashLeftSemiJoin.ts @@ -0,0 +1,25 @@ +// License: LGPL-3.0-or-later +// from https://github.com/mtraynham/lodash-joins/blob/c252b462981562451d85d1e09c8f273ce7fe06c5/lib/hash/hashLeftSemiJoin.ts +import filter from 'lodash/filter'; +import has from 'lodash/has'; +import keyBy from 'lodash/keyBy'; + +import {Accessor} from '../typings'; +import {toStringAccessor} from './util'; + +/** + * Hash left semi join + */ +export default function hashLeftSemiJoin( + a: LeftRow[], + aAccessor: Accessor, + b: RightRow[], + bAccessor: Accessor +): LeftRow[] { + if (a.length < 1 || b.length < 1) { + return []; + } + const index: {[key: string]: RightRow} = keyBy(b, toStringAccessor(bAccessor)), + leftAccessor: Accessor = toStringAccessor(aAccessor); + return filter(a, (aDatum: LeftRow) => has(index, leftAccessor(aDatum))); +} diff --git a/app/javascript/common/lodash-joins/hash/hashRightAntiJoin.ts b/app/javascript/common/lodash-joins/hash/hashRightAntiJoin.ts new file mode 100644 index 00000000..68f6693f --- /dev/null +++ b/app/javascript/common/lodash-joins/hash/hashRightAntiJoin.ts @@ -0,0 +1,17 @@ +// License: LGPL-3.0-or-later +// from https://github.com/mtraynham/lodash-joins/blob/c252b462981562451d85d1e09c8f273ce7fe06c5/lib/hash/hashRightAntiJoin.ts +import hashLeftAntiJoin from './hashLeftAntiJoin'; + +import {Accessor} from '../typings'; + +/** + * Hash right anti join + */ +export default function hashRightAntiJoin( + a: LeftRow[], + aAccessor: Accessor, + b: RightRow[], + bAccessor: Accessor +): RightRow[] { + return hashLeftAntiJoin(b, bAccessor, a, aAccessor); +} diff --git a/app/javascript/common/lodash-joins/hash/hashRightOuterJoin.ts b/app/javascript/common/lodash-joins/hash/hashRightOuterJoin.ts new file mode 100644 index 00000000..e4127a21 --- /dev/null +++ b/app/javascript/common/lodash-joins/hash/hashRightOuterJoin.ts @@ -0,0 +1,18 @@ +// License: LGPL-3.0-or-later +// from https://github.com/mtraynham/lodash-joins/blob/c252b462981562451d85d1e09c8f273ce7fe06c5/lib/hash/hashRightOuterJoin.ts +import hashLeftOuterJoin from './hashLeftOuterJoin'; + +import {Accessor, Merger} from '../typings'; + +/** + * Hash right outer join + */ +export default function hashRightOuterJoin( + a: LeftRow[], + aAccessor: Accessor, + b: RightRow[], + bAccessor: Accessor, + merger: Merger +): MergeResult[] { + return hashLeftOuterJoin(b, bAccessor, a, aAccessor, merger); +} diff --git a/app/javascript/common/lodash-joins/hash/hashRightSemiJoin.ts b/app/javascript/common/lodash-joins/hash/hashRightSemiJoin.ts new file mode 100644 index 00000000..76e014e7 --- /dev/null +++ b/app/javascript/common/lodash-joins/hash/hashRightSemiJoin.ts @@ -0,0 +1,17 @@ +// License: LGPL-3.0-or-later +// from https://github.com/mtraynham/lodash-joins/blob/c252b462981562451d85d1e09c8f273ce7fe06c5/lib/hash/hashRightSemiJoin.ts +import hashLeftSemiJoin from './hashLeftSemiJoin'; + +import {Accessor} from '../typings'; + +/** + * Hash right semi join + */ +export default function hashRightSemiJoin( + a: LeftRow[], + aAccessor: Accessor, + b: RightRow[], + bAccessor: Accessor +): RightRow[] { + return hashLeftSemiJoin(b, bAccessor, a, aAccessor); +} diff --git a/app/javascript/common/lodash-joins/hash/index.spec.ts b/app/javascript/common/lodash-joins/hash/index.spec.ts new file mode 100644 index 00000000..e730969d --- /dev/null +++ b/app/javascript/common/lodash-joins/hash/index.spec.ts @@ -0,0 +1,214 @@ +// License: LGPL-3.0-or-later +// from https://github.com/mtraynham/lodash-joins/blob/c252b462981562451d85d1e09c8f273ce7fe06c5/lib/hash/index.spec.ts +import assign from 'lodash/assign'; +import hashFullOuterJoin from './hashFullOuterJoin'; +import hashInnerJoin from './hashInnerJoin'; +import hashLeftAntiJoin from './hashLeftAntiJoin'; +import hashLeftOuterJoin from './hashLeftOuterJoin'; +import hashLeftSemiJoin from './hashLeftSemiJoin'; +import hashRightAntiJoin from './hashRightAntiJoin'; +import hashRightOuterJoin from './hashRightOuterJoin'; +import hashRightSemiJoin from './hashRightSemiJoin'; +import {Accessor, Merger} from '../typings'; + +interface Row { + id: string; + left?: number; + right?: number; +} + +describe('Hash Joins', () => { + const left: Row[] = [ + {id: 'c', left: 0}, + {id: 'c', left: 1}, + {id: 'e', left: 2} + ]; + const right: Row[] = [ + {id: 'a', right: 0}, + {id: 'b', right: 1}, + {id: 'c', right: 2}, + {id: 'c', right: 3}, + {id: 'd', right: 4}, + {id: 'f', right: 5}, + {id: 'g', right: 6} + ]; + const accessor: Accessor = (obj: Row): string => obj.id; + const merger: Merger = (l: Row, r: Row): Row => assign({}, l, r); + describe('#hashFullOuterJoin()', () => { + const expectedA = [ + {id: 'a', right: 0}, + {id: 'b', right: 1}, + {id: 'c', left: 0, right: 2}, + {id: 'c', left: 1, right: 2}, + {id: 'c', left: 0, right: 3}, + {id: 'c', left: 1, right: 3}, + {id: 'd', right: 4}, + {id: 'f', right: 5}, + {id: 'g', right: 6}, + {id: 'e', left: 2} + ], + expectedB = [ + {id: 'a', right: 0}, + {id: 'b', right: 1}, + {id: 'c', right: 2, left: 0}, + {id: 'c', right: 2, left: 1}, + {id: 'c', right: 3, left: 0}, + {id: 'c', right: 3, left: 1}, + {id: 'd', right: 4}, + {id: 'f', right: 5}, + {id: 'g', right: 6}, + {id: 'e', left: 2} + ], + resultA = hashFullOuterJoin(left, accessor, right, accessor, merger), + resultB = hashFullOuterJoin(right, accessor, left, accessor, merger), + resultC = hashFullOuterJoin([], accessor, [], accessor, merger), + resultD = hashFullOuterJoin(left, accessor, [], accessor, merger), + resultE = hashFullOuterJoin([], accessor, right, accessor, merger); + it('should return 10 rows if parent is left', () => + expect(resultA.length).toBe(10)); + it('should match the expected output if parent is left', () => + expect(resultA).toEqual(expectedA)); + it('should return 8 rows if parent is right', () => + expect(resultB.length).toBe(10)); + it('should match the expected output if parent is right', () => + expect(resultB).toEqual(expectedB)); + it('should return empty results for empty input', () => + expect(resultC.length).toBe(0)); + it('should return just the left side if empty right side', () => + expect(resultD.length).toBe(left.length)); + it('should return just the right side if empty left side', () => + expect(resultE.length).toBe(right.length)); + }); + describe('#hashInnerJoin()', () => { + const expectedA = [ + {id: 'c', left: 0, right: 2}, + {id: 'c', left: 1, right: 2}, + {id: 'c', left: 0, right: 3}, + {id: 'c', left: 1, right: 3} + ], + expectedB = [ + {id: 'c', right: 2, left: 0}, + {id: 'c', right: 2, left: 1}, + {id: 'c', right: 3, left: 0}, + {id: 'c', right: 3, left: 1} + ], + resultA = hashInnerJoin(left, accessor, right, accessor, merger), + resultB = hashInnerJoin(right, accessor, left, accessor, merger), + resultC = hashInnerJoin([], accessor, right, accessor, merger); + it('should return 5 rows if parent is left', () => + expect(resultA.length).toBe(4)); + it('should match the expected output if parent is left', () => + expect(resultA).toEqual(expectedA)); + it('should return 5 rows if parent is right', () => + expect(resultB.length).toBe(4)); + it('should match the expected output if parent is right', () => + expect(resultB).toEqual(expectedB)); + it('should return empty results for empty input', () => + expect(resultC.length).toBe(0)); + }); + describe('#hashLeftAntiJoin()', () => { + const expected = [ + {id: 'e', left: 2} + ], + result = hashLeftAntiJoin(left, accessor, right, accessor), + resultB = hashLeftAntiJoin([], accessor, right, accessor); + it('should return 1 rows', () => + expect(result.length).toBe(1)); + it('should match the expected output', () => + expect(result).toEqual(expected)); + it('should return empty results for empty input', () => + expect(resultB.length).toBe(0)); + }); + describe('#hashLeftOuterJoin()', () => { + const expected = [ + {id: 'c', left: 0, right: 2}, + {id: 'c', left: 1, right: 2}, + {id: 'c', left: 0, right: 3}, + {id: 'c', left: 1, right: 3}, + {id: 'e', left: 2} + ], + result = hashLeftOuterJoin(left, accessor, right, accessor, merger), + resultB = hashLeftOuterJoin([], accessor, right, accessor, merger), + resultC = hashLeftOuterJoin(left, accessor, [], accessor, merger); + it('should return 5 rows', () => + expect(result.length).toBe(5)); + it('should match the expected output', () => + expect(result).toEqual(expected)); + it('should return empty results for empty input', () => + expect(resultB.length).toBe(0)); + it('should return just the left side if empty right side', () => + expect(resultC.length).toBe(left.length)); + }); + describe('#hashLeftSemiJoin()', () => { + const expected = [ + {id: 'c', left: 0}, + {id: 'c', left: 1} + ], + result = hashLeftSemiJoin(left, accessor, right, accessor), + resultB = hashLeftSemiJoin([], accessor, right, accessor); + it('should return 2 rows', () => + expect(result.length).toBe(2)); + it('should match the expected output', () => + expect(result).toEqual(expected)); + it('should return empty results for empty input', () => + expect(resultB.length).toBe(0)); + }); + describe('#hashRightAntiJoin()', () => { + const expected = [ + {id: 'a', right: 0}, + {id: 'b', right: 1}, + {id: 'd', right: 4}, + {id: 'f', right: 5}, + {id: 'g', right: 6} + ], + result = hashRightAntiJoin(left, accessor, right, accessor), + resultB = hashRightAntiJoin(left, accessor, [], accessor); + it('should return 5 rows', () => + expect(result.length).toBe(5)); + it('should match the expected output', () => + expect(result).toEqual(expected)); + it('should match the left anti join with right as the parent', () => + expect(hashLeftAntiJoin(right, accessor, left, accessor)).toEqual(result)); + it('should return empty results for empty input', () => + expect(resultB.length).toBe(0)); + }); + describe('#hashRightOuterJoin()', () => { + const expected = [ + {id: 'a', right: 0}, + {id: 'b', right: 1}, + {id: 'c', right: 2, left: 0}, + {id: 'c', right: 2, left: 1}, + {id: 'c', right: 3, left: 0}, + {id: 'c', right: 3, left: 1}, + {id: 'd', right: 4}, + {id: 'f', right: 5}, + {id: 'g', right: 6} + ], + result = hashRightOuterJoin(left, accessor, right, accessor, merger), + resultB = hashRightOuterJoin(left, accessor, [], accessor, merger); + it('should return 9 rows', () => + expect(result.length).toBe(9)); + it('should match the expected output', () => + expect(result).toEqual(expected)); + it('should match the left outer join with right as the parent', () => + expect(hashLeftOuterJoin(right, accessor, left, accessor, merger)).toEqual(result)); + it('should return empty results for empty input', () => + expect(resultB.length).toBe(0)); + }); + describe('#hashRightSemiJoin()', () => { + const expected = [ + {id: 'c', right: 2}, + {id: 'c', right: 3} + ], + result = hashRightSemiJoin(left, accessor, right, accessor), + resultB = hashRightSemiJoin(left, accessor, [], accessor); + it('should return 2 rows', () => + expect(result.length).toBe(2)); + it('should match the expected output', () => + expect(result).toEqual(expected)); + it('should match the left semi join with right as the parent', () => + expect(hashLeftSemiJoin(right, accessor, left, accessor)).toEqual(result)); + it('should return empty results for empty input', () => + expect(resultB.length).toBe(0)); + }); +}); diff --git a/app/javascript/common/lodash-joins/hash/index.ts b/app/javascript/common/lodash-joins/hash/index.ts new file mode 100644 index 00000000..c50f6241 --- /dev/null +++ b/app/javascript/common/lodash-joins/hash/index.ts @@ -0,0 +1,21 @@ +// License: LGPL-3.0-or-later +// from https://github.com/mtraynham/lodash-joins/blob/c252b462981562451d85d1e09c8f273ce7fe06c5/lib/hash/index.ts +import hashFullOuterJoin from './hashFullOuterJoin'; +import hashInnerJoin from './hashInnerJoin'; +import hashLeftAntiJoin from './hashLeftAntiJoin'; +import hashLeftOuterJoin from './hashLeftOuterJoin'; +import hashLeftSemiJoin from './hashLeftSemiJoin'; +import hashRightAntiJoin from './hashRightAntiJoin'; +import hashRightOuterJoin from './hashRightOuterJoin'; +import hashRightSemiJoin from './hashRightSemiJoin'; + +export { + hashFullOuterJoin, + hashInnerJoin, + hashLeftAntiJoin, + hashLeftOuterJoin, + hashLeftSemiJoin, + hashRightAntiJoin, + hashRightOuterJoin, + hashRightSemiJoin +}; diff --git a/app/javascript/common/lodash-joins/hash/util/index.ts b/app/javascript/common/lodash-joins/hash/util/index.ts new file mode 100644 index 00000000..bd97f60c --- /dev/null +++ b/app/javascript/common/lodash-joins/hash/util/index.ts @@ -0,0 +1,7 @@ +// License: LGPL-3.0-or-later +// from https://github.com/mtraynham/lodash-joins/blob/c252b462981562451d85d1e09c8f273ce7fe06c5/lib/hash/util/index.ts +import toStringAccessor from './toStringAccessor'; + +export { + toStringAccessor +}; diff --git a/app/javascript/common/lodash-joins/hash/util/toStringAccessor.ts b/app/javascript/common/lodash-joins/hash/util/toStringAccessor.ts new file mode 100644 index 00000000..91c854a5 --- /dev/null +++ b/app/javascript/common/lodash-joins/hash/util/toStringAccessor.ts @@ -0,0 +1,11 @@ +// License: LGPL-3.0-or-later +// from https://github.com/mtraynham/lodash-joins/blob/c252b462981562451d85d1e09c8f273ce7fe06c5/lib/hash/util/toStringAccessor.ts +import toString from 'lodash/toString'; + +import {Accessor} from '../../typings'; + +export default function toStringAccessor( + accessor: Accessor +): Accessor { + return (row: Row): string => toString(accessor(row)); +} diff --git a/app/javascript/common/lodash-joins/typings.ts b/app/javascript/common/lodash-joins/typings.ts new file mode 100644 index 00000000..b38fc0cf --- /dev/null +++ b/app/javascript/common/lodash-joins/typings.ts @@ -0,0 +1,28 @@ +// License: LGPL-3.0-or-later +// from https://github.com/mtraynham/lodash-joins/blob/c252b462981562451d85d1e09c8f273ce7fe06c5/lib/typings.ts +export interface Accessor extends Function { + (a: Row): Key; +} + +export interface Merger extends Function { + (left: LeftRow, right: RightRow): MergeResult; +} + +export interface Join extends Function { + ( + left: LeftRow[], + leftAccessor: Accessor, + right: RightRow[], + rightAccessor: Accessor, + merger: Merger + ): MergeResult[]; +} + +export interface NonMergeJoin extends Function { + ( + left: LeftRow[], + leftAccessor: Accessor, + right: RightRow[], + rightAccessor: Accessor + ): LeftRow[] | RightRow[]; +} diff --git a/app/javascript/common/lodash-joins/util/basicAccessor.ts b/app/javascript/common/lodash-joins/util/basicAccessor.ts new file mode 100644 index 00000000..9e5cee58 --- /dev/null +++ b/app/javascript/common/lodash-joins/util/basicAccessor.ts @@ -0,0 +1,19 @@ +// License: LGPL-3.0-or-later +// from https://github.com/mtraynham/lodash-joins/blob/c252b462981562451d85d1e09c8f273ce7fe06c5/lib/util/basicAccessor.ts +import isArray from 'lodash/isArray'; +import isString from 'lodash/isString'; +import property from 'lodash/property'; + +import {Accessor} from '../typings'; + +/** + * Create an accessor from a string, string[] or a different accessor. + * If it's a string or an array, use _.property. + */ +export default function basicAccessor( + obj: Accessor | string | string[] +): Accessor { + return isString(obj) || isArray(obj) ? + property(obj) : + obj; +} diff --git a/app/javascript/common/lodash-joins/util/basicMerger.ts b/app/javascript/common/lodash-joins/util/basicMerger.ts new file mode 100644 index 00000000..6b077fa8 --- /dev/null +++ b/app/javascript/common/lodash-joins/util/basicMerger.ts @@ -0,0 +1,13 @@ +// License: LGPL-3.0-or-later +// from https://github.com/mtraynham/lodash-joins/blob/c252b462981562451d85d1e09c8f273ce7fe06c5/lib/util/basicMerger.ts +import assign from 'lodash/assign'; + +/** + * The default merger just creates a combined object using _.assign. + */ +export default function basicMerger( + left: LeftRow, + right: RightRow, +): LeftRow & RightRow { + return assign({}, left, right); +} diff --git a/app/javascript/common/lodash-joins/util/index.ts b/app/javascript/common/lodash-joins/util/index.ts new file mode 100644 index 00000000..17590bc0 --- /dev/null +++ b/app/javascript/common/lodash-joins/util/index.ts @@ -0,0 +1,11 @@ +// License: LGPL-3.0-or-later +// from https://github.com/mtraynham/lodash-joins/blob/c252b462981562451d85d1e09c8f273ce7fe06c5/lib/util/index.ts +import basicAccessor from './basicAccessor'; +import basicMerger from './basicMerger'; +import joinWrapper from './joinWrapper'; + +export { + basicAccessor, + basicMerger, + joinWrapper +}; diff --git a/app/javascript/common/lodash-joins/util/joinWrapper.ts b/app/javascript/common/lodash-joins/util/joinWrapper.ts new file mode 100644 index 00000000..bf1b7c03 --- /dev/null +++ b/app/javascript/common/lodash-joins/util/joinWrapper.ts @@ -0,0 +1,49 @@ +// License: LGPL-3.0-or-later +// from https://github.com/mtraynham/lodash-joins/blob/c252b462981562451d85d1e09c8f273ce7fe06c5/lib/util/joinWrapper.ts +import {Accessor, Join, Merger, NonMergeJoin} from '../typings'; +import basicAccessor from './basicAccessor'; +import basicMerger from './basicMerger'; + +/** + * Wrap a join function to process inputs in a more succinct manner. + */ +/* eslint-disable @typescript-eslint/no-explicit-any,@typescript-eslint/consistent-type-assertions */ +function joinWrapper( + joinFn: NonMergeJoin +): NonMergeJoin; +function joinWrapper( + joinFn: NonMergeJoin +): NonMergeJoin; +function joinWrapper( + joinFn: Join +): Join; +function joinWrapper( + joinFn: Join +): Join; +function joinWrapper( + joinFn: Join +): Join { + return ( + a: LeftRow[], + aAccessor: Accessor, + b: RightRow[] = a, + bAccessor: Accessor = aAccessor, + merger: Merger = basicMerger + ): MergeResult[] => { + if (!a) { + throw new Error('Missing required left array'); + } else if (!aAccessor) { + throw new Error('Missing required left accessor'); + } + return joinFn( + a, + basicAccessor(aAccessor), + b, + basicAccessor(bAccessor), + merger + ); + }; +} +/* eslint-enable @typescript-eslint/no-explicit-any,@typescript-eslint/consistent-type-assertions */ + +export default joinWrapper; diff --git a/included.json b/included.json index 5c8b79e2..303bc885 100644 --- a/included.json +++ b/included.json @@ -4,6 +4,10 @@ { "name": "js-money", "version": "0.6.3" + }, + { + "name": "lodash-joins", + "version": "3.0.1" } ] } \ No newline at end of file