-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[H-0008] findByPrimaryKey is reworked
- Loading branch information
Kovalenkov Pavel
committed
Feb 5, 2023
1 parent
89930bf
commit 44c911f
Showing
14 changed files
with
187 additions
and
97 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from "./nodeItem"; | ||
export * from "./nestedNodes"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
interface INodeItem { | ||
id: string; | ||
value: string; | ||
children?: INodeItem[]; | ||
} | ||
|
||
const nodeItem: INodeItem = { | ||
id: "0", | ||
value: "0", | ||
}; | ||
|
||
export { nodeItem }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { findByPrimaryKey } from "../findByPrimaryKey"; | ||
import { | ||
INodeItem, | ||
nestedNodeItem, | ||
nestedNodeItemDeep, | ||
nestedNodeItems, | ||
nodeItem, | ||
} from "../__mocks__"; | ||
|
||
describe("findByPrimaryKey", () => { | ||
const primaryKey = "id"; | ||
const secondaryKey = "children"; | ||
|
||
test("finds object by a given primary key in a plain structure", () => { | ||
expect(findByPrimaryKey(primaryKey, secondaryKey)([nodeItem], "0")).toBe(nodeItem); | ||
}); | ||
|
||
test("finds object by a given primary key in a nested structure (nesting level 1)", () => { | ||
expect(findByPrimaryKey(primaryKey, secondaryKey)(nestedNodeItems, "1-1")).toBe(nestedNodeItem); | ||
}); | ||
|
||
test("finds object by a given primary key in a nested structure (nesting level 2)", () => { | ||
expect(findByPrimaryKey(primaryKey, secondaryKey)(nestedNodeItems, "1-2-1")).toBe( | ||
nestedNodeItemDeep, | ||
); | ||
}); | ||
|
||
test("returns 'null' if value by a given primary key doesn't exist", () => { | ||
expect(findByPrimaryKey(primaryKey, secondaryKey)(nestedNodeItems, "1-2-3")).toBeNull(); | ||
}); | ||
|
||
test("calls a mutation callback (if provided) on a found node", () => { | ||
const mutation = (node: INodeItem) => (node.value = `${node.value}-mutated`); | ||
const nodeWithMutation = findByPrimaryKey(primaryKey, secondaryKey)( | ||
nestedNodeItems, | ||
"1-1", | ||
mutation, | ||
); | ||
|
||
expect(nodeWithMutation?.value).toBe("v-1-1-mutated"); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { findByPrimaryKey } from "../findByPrimaryKey"; | ||
import { initListUtils } from "../initListUtils"; | ||
|
||
jest.mock("../findByPrimaryKey"); | ||
|
||
describe("initListUtils", () => { | ||
const primaryKey = "id"; | ||
const childrenKey = "children"; | ||
|
||
afterEach(jest.clearAllMocks); | ||
|
||
test("during initialization, calls 'findByPrimaryKey' utility with proper arguments", () => { | ||
initListUtils({ primaryKey, childrenKey }); | ||
|
||
expect(findByPrimaryKey).toBeCalledWith(primaryKey, childrenKey); | ||
}); | ||
|
||
test("provides a result of a proper signature", () => { | ||
(findByPrimaryKey as jest.Mock).mockImplementationOnce(() => jest.fn()); | ||
|
||
const utils = initListUtils({ primaryKey, childrenKey }); | ||
|
||
expect(utils).toMatchObject({ | ||
findByPrimaryKey: expect.any(Function), | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
type PartialRecord<K extends keyof any, T> = { | ||
[P in K]?: T; | ||
}; | ||
|
||
interface IFindByPrimaryKeyMutation<T extends Record<string, unknown>> { | ||
(node: T): void; | ||
} | ||
|
||
/** | ||
* @param primaryKey primary key name which is a unique identifier for each object within the given list. | ||
* @param childrenKey secondary key name which is used as an identifier for nested nodes list within a current one. | ||
* @returns function that accepts: | ||
* 1) list to traverse over; | ||
* 2) value of a primary key to match; | ||
* 3) callback to be called on a found node. | ||
* | ||
* Say, our list is something like that: | ||
* | ||
* const list = [{ id: 0, value: '0', children: [{ id: 1, value: '1' }] }]; | ||
* | ||
* Then, we can find an object with id === 1 doing the following: | ||
* | ||
* const node = findByPrimaryKey('id', 'children')(list, 1); | ||
* @returns if target node exists - the link to that node itself, otherwise - null | ||
*/ | ||
const findByPrimaryKey = | ||
<PK extends string, SK extends string>(primaryKey: PK, childrenKey: SK) => | ||
<T extends Record<PK, T[PK]> & PartialRecord<SK, T[]>>( | ||
items: T[], | ||
value: T[PK], | ||
cb?: IFindByPrimaryKeyMutation<T>, | ||
) => { | ||
let foundItem: T | null = null; | ||
|
||
const find = (children: T[]) => { | ||
for (let i = 0; i < children.length; i++) { | ||
const current = children[i]; | ||
|
||
if (current[primaryKey] === value) { | ||
foundItem = current; | ||
break; | ||
} | ||
|
||
const next = current[childrenKey]; | ||
|
||
if (next && Array.isArray(next)) { | ||
find(next); | ||
} | ||
} | ||
|
||
return foundItem; | ||
}; | ||
|
||
const result = find(items); | ||
|
||
if (cb && result) { | ||
cb(result); | ||
} | ||
|
||
return result; | ||
}; | ||
|
||
export type { IFindByPrimaryKeyMutation }; | ||
|
||
export { findByPrimaryKey }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { initListUtils } from "./initListUtils"; | ||
export { findByPrimaryKey } from "./findByPrimaryKey"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { findByPrimaryKey } from "./findByPrimaryKey"; | ||
|
||
interface IInitListUtilsOptions<PK, SK> { | ||
primaryKey: PK; | ||
childrenKey: SK; | ||
} | ||
|
||
/** | ||
* Creates a bag of useful traversing utilities for going over, finding and mutating nodes within | ||
* some nested objects structures. | ||
* For now, contains following methods: | ||
* - findByPrimaryKey - finds a node by it's primary identifier and invokes provided callback to mutate the node. | ||
*/ | ||
function initListUtils<PK extends string, SK extends string>( | ||
options: IInitListUtilsOptions<PK, SK>, | ||
) { | ||
const { primaryKey, childrenKey } = options; | ||
|
||
return { | ||
findByPrimaryKey: findByPrimaryKey(primaryKey, childrenKey), | ||
}; | ||
} | ||
|
||
export type { IInitListUtilsOptions }; | ||
|
||
export { initListUtils }; |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.