Add lodash-joins
This commit is contained in:
parent
40fdd7a8b9
commit
0e9ab03352
20 changed files with 660 additions and 1 deletions
|
@ -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
|
||||
app/javascript/legacy_react/src/components/session_login_page/SessionLoginPage.tsx
|
||||
|
||||
#included code from another package
|
||||
app/javascript/common/lodash-joins
|
|
@ -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
|
||||
|
|
72
app/javascript/common/lodash-joins/hash/hashFullOuterJoin.ts
Normal file
72
app/javascript/common/lodash-joins/hash/hashFullOuterJoin.ts
Normal file
|
@ -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<LeftRow, RightRow, Key, MergeResult>(
|
||||
a: LeftRow[],
|
||||
aAccessor: Accessor<LeftRow, Key>,
|
||||
b: RightRow[],
|
||||
bAccessor: Accessor<RightRow, Key>,
|
||||
merger: Merger<LeftRow | undefined, RightRow | undefined, MergeResult>
|
||||
): 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<LeftRow, string> = toStringAccessor(aAccessor),
|
||||
rightAccessor: Accessor<RightRow, string> = 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)));
|
||||
}
|
46
app/javascript/common/lodash-joins/hash/hashInnerJoin.ts
Normal file
46
app/javascript/common/lodash-joins/hash/hashInnerJoin.ts
Normal file
|
@ -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<LeftRow, RightRow, Key, MergeResult>(
|
||||
a: LeftRow[],
|
||||
aAccessor: Accessor<LeftRow, Key>,
|
||||
b: RightRow[],
|
||||
bAccessor: Accessor<RightRow, Key>,
|
||||
merger: Merger<LeftRow, RightRow, MergeResult>
|
||||
): MergeResult[] {
|
||||
if (a.length < 1 || b.length < 1) {
|
||||
return [];
|
||||
}
|
||||
const leftAccessor: Accessor<LeftRow, string> = toStringAccessor(aAccessor),
|
||||
rightAccessor: Accessor<RightRow, string> = 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;
|
||||
}, []);
|
||||
}
|
25
app/javascript/common/lodash-joins/hash/hashLeftAntiJoin.ts
Normal file
25
app/javascript/common/lodash-joins/hash/hashLeftAntiJoin.ts
Normal file
|
@ -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<LeftRow, RightRow, Key>(
|
||||
a: LeftRow[],
|
||||
aAccessor: Accessor<LeftRow, Key>,
|
||||
b: RightRow[],
|
||||
bAccessor: Accessor<RightRow, Key>
|
||||
): LeftRow[] {
|
||||
if (a.length < 1 || b.length < 1) {
|
||||
return a;
|
||||
}
|
||||
const index: {[key: string]: RightRow} = keyBy(b, toStringAccessor(bAccessor)),
|
||||
leftAccessor: Accessor<LeftRow, string> = toStringAccessor(aAccessor);
|
||||
return filter(a, (aDatum: LeftRow) => !has(index, leftAccessor(aDatum)));
|
||||
}
|
57
app/javascript/common/lodash-joins/hash/hashLeftOuterJoin.ts
Normal file
57
app/javascript/common/lodash-joins/hash/hashLeftOuterJoin.ts
Normal file
|
@ -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<LeftRow, RightRow, Key, MergeResult>(
|
||||
a: LeftRow[],
|
||||
aAccessor: Accessor<LeftRow, Key>,
|
||||
b: RightRow[],
|
||||
bAccessor: Accessor<RightRow, Key>,
|
||||
merger: Merger<LeftRow, RightRow | undefined, MergeResult>
|
||||
): MergeResult[] {
|
||||
if (a.length < 1 || b.length < 1) {
|
||||
return map(a, (a: LeftRow) => merger(a, undefined));
|
||||
}
|
||||
const leftAccessor: Accessor<LeftRow, string> = toStringAccessor(aAccessor),
|
||||
rightAccessor: Accessor<RightRow, string> = 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;
|
||||
}, []);
|
||||
}
|
25
app/javascript/common/lodash-joins/hash/hashLeftSemiJoin.ts
Normal file
25
app/javascript/common/lodash-joins/hash/hashLeftSemiJoin.ts
Normal file
|
@ -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<LeftRow, RightRow, Key>(
|
||||
a: LeftRow[],
|
||||
aAccessor: Accessor<LeftRow, Key>,
|
||||
b: RightRow[],
|
||||
bAccessor: Accessor<RightRow, Key>
|
||||
): LeftRow[] {
|
||||
if (a.length < 1 || b.length < 1) {
|
||||
return [];
|
||||
}
|
||||
const index: {[key: string]: RightRow} = keyBy(b, toStringAccessor(bAccessor)),
|
||||
leftAccessor: Accessor<LeftRow, string> = toStringAccessor(aAccessor);
|
||||
return filter(a, (aDatum: LeftRow) => has(index, leftAccessor(aDatum)));
|
||||
}
|
17
app/javascript/common/lodash-joins/hash/hashRightAntiJoin.ts
Normal file
17
app/javascript/common/lodash-joins/hash/hashRightAntiJoin.ts
Normal file
|
@ -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<LeftRow, RightRow, Key>(
|
||||
a: LeftRow[],
|
||||
aAccessor: Accessor<LeftRow, Key>,
|
||||
b: RightRow[],
|
||||
bAccessor: Accessor<RightRow, Key>
|
||||
): RightRow[] {
|
||||
return hashLeftAntiJoin(b, bAccessor, a, aAccessor);
|
||||
}
|
|
@ -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<LeftRow, RightRow, Key, MergeResult>(
|
||||
a: LeftRow[],
|
||||
aAccessor: Accessor<LeftRow, Key>,
|
||||
b: RightRow[],
|
||||
bAccessor: Accessor<RightRow, Key>,
|
||||
merger: Merger<RightRow, LeftRow, MergeResult>
|
||||
): MergeResult[] {
|
||||
return hashLeftOuterJoin(b, bAccessor, a, aAccessor, merger);
|
||||
}
|
17
app/javascript/common/lodash-joins/hash/hashRightSemiJoin.ts
Normal file
17
app/javascript/common/lodash-joins/hash/hashRightSemiJoin.ts
Normal file
|
@ -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<LeftRow, RightRow, Key>(
|
||||
a: LeftRow[],
|
||||
aAccessor: Accessor<LeftRow, Key>,
|
||||
b: RightRow[],
|
||||
bAccessor: Accessor<RightRow, Key>
|
||||
): RightRow[] {
|
||||
return hashLeftSemiJoin(b, bAccessor, a, aAccessor);
|
||||
}
|
214
app/javascript/common/lodash-joins/hash/index.spec.ts
Normal file
214
app/javascript/common/lodash-joins/hash/index.spec.ts
Normal file
|
@ -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<Row, string> = (obj: Row): string => obj.id;
|
||||
const merger: Merger<Row, Row, Row> = (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));
|
||||
});
|
||||
});
|
21
app/javascript/common/lodash-joins/hash/index.ts
Normal file
21
app/javascript/common/lodash-joins/hash/index.ts
Normal file
|
@ -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
|
||||
};
|
7
app/javascript/common/lodash-joins/hash/util/index.ts
Normal file
7
app/javascript/common/lodash-joins/hash/util/index.ts
Normal file
|
@ -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
|
||||
};
|
|
@ -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<Row, Key>(
|
||||
accessor: Accessor<Row, Key>
|
||||
): Accessor<Row, string> {
|
||||
return (row: Row): string => toString(accessor(row));
|
||||
}
|
28
app/javascript/common/lodash-joins/typings.ts
Normal file
28
app/javascript/common/lodash-joins/typings.ts
Normal file
|
@ -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<Row, Key> extends Function {
|
||||
(a: Row): Key;
|
||||
}
|
||||
|
||||
export interface Merger<LeftRow, RightRow, MergeResult> extends Function {
|
||||
(left: LeftRow, right: RightRow): MergeResult;
|
||||
}
|
||||
|
||||
export interface Join<LeftRow, RightRow, Key, MergeResult> extends Function {
|
||||
(
|
||||
left: LeftRow[],
|
||||
leftAccessor: Accessor<LeftRow, Key>,
|
||||
right: RightRow[],
|
||||
rightAccessor: Accessor<RightRow, Key>,
|
||||
merger: Merger<LeftRow, RightRow, MergeResult>
|
||||
): MergeResult[];
|
||||
}
|
||||
|
||||
export interface NonMergeJoin<LeftRow, RightRow, Key> extends Function {
|
||||
(
|
||||
left: LeftRow[],
|
||||
leftAccessor: Accessor<LeftRow, Key>,
|
||||
right: RightRow[],
|
||||
rightAccessor: Accessor<RightRow, Key>
|
||||
): LeftRow[] | RightRow[];
|
||||
}
|
19
app/javascript/common/lodash-joins/util/basicAccessor.ts
Normal file
19
app/javascript/common/lodash-joins/util/basicAccessor.ts
Normal file
|
@ -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<Row, Key>(
|
||||
obj: Accessor<Row, Key> | string | string[]
|
||||
): Accessor<Row, Key> {
|
||||
return isString(obj) || isArray(obj) ?
|
||||
property(obj) :
|
||||
obj;
|
||||
}
|
13
app/javascript/common/lodash-joins/util/basicMerger.ts
Normal file
13
app/javascript/common/lodash-joins/util/basicMerger.ts
Normal file
|
@ -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<LeftRow, RightRow>(
|
||||
left: LeftRow,
|
||||
right: RightRow,
|
||||
): LeftRow & RightRow {
|
||||
return assign({}, left, right);
|
||||
}
|
11
app/javascript/common/lodash-joins/util/index.ts
Normal file
11
app/javascript/common/lodash-joins/util/index.ts
Normal file
|
@ -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
|
||||
};
|
49
app/javascript/common/lodash-joins/util/joinWrapper.ts
Normal file
49
app/javascript/common/lodash-joins/util/joinWrapper.ts
Normal file
|
@ -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<LeftRow, Key>(
|
||||
joinFn: NonMergeJoin<LeftRow, LeftRow, Key>
|
||||
): NonMergeJoin<LeftRow, LeftRow, Key>;
|
||||
function joinWrapper<LeftRow, RightRow, Key>(
|
||||
joinFn: NonMergeJoin<LeftRow, RightRow, Key>
|
||||
): NonMergeJoin<LeftRow, RightRow, Key>;
|
||||
function joinWrapper<LeftRow, Key>(
|
||||
joinFn: Join<LeftRow, LeftRow, Key, LeftRow>
|
||||
): Join<LeftRow, LeftRow, Key, LeftRow>;
|
||||
function joinWrapper<LeftRow, RightRow, Key>(
|
||||
joinFn: Join<LeftRow, RightRow, Key, LeftRow & RightRow>
|
||||
): Join<LeftRow, RightRow, Key, LeftRow & RightRow>;
|
||||
function joinWrapper<LeftRow, RightRow, Key, MergeResult>(
|
||||
joinFn: Join<LeftRow, RightRow, Key, MergeResult>
|
||||
): Join<LeftRow, RightRow, Key, MergeResult> {
|
||||
return (
|
||||
a: LeftRow[],
|
||||
aAccessor: Accessor<LeftRow, Key>,
|
||||
b: RightRow[] = <any> a,
|
||||
bAccessor: Accessor<RightRow, Key> = <any> aAccessor,
|
||||
merger: Merger<LeftRow, RightRow, MergeResult> = <any> 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;
|
|
@ -4,6 +4,10 @@
|
|||
{
|
||||
"name": "js-money",
|
||||
"version": "0.6.3"
|
||||
},
|
||||
{
|
||||
"name": "lodash-joins",
|
||||
"version": "3.0.1"
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue