From 13fea2378733a30775d39132a1d4e6623d422e41 Mon Sep 17 00:00:00 2001 From: Andrei Dumitrescu <5057797+andreidmt@users.noreply.github.com> Date: Thu, 3 Dec 2020 22:09:53 +0100 Subject: [PATCH] feat: Switch logic of "pluck" and "pick". Update "pluck" to accept object arrays. BREAKING CHANGE: "pick" for extracting one property, "pluck" for multiple. Ramda uses "pick" for plural and "pluck" for singular, RethinkDB the other way around. Going with Rethink. --- src/pick/pick.js | 48 +++++++++++++++++------------- src/pick/pick.test.js | 29 +++++++++--------- src/pluck/pluck.js | 66 +++++++++++++++++++++++++++++++---------- src/pluck/pluck.test.js | 64 +++++++++++++++++++++++++++++---------- 4 files changed, 142 insertions(+), 65 deletions(-) diff --git a/src/pick/pick.js b/src/pick/pick.js index 227133e..d54cb04 100644 --- a/src/pick/pick.js +++ b/src/pick/pick.js @@ -1,34 +1,40 @@ -import { curry } from "../curry/curry" - -const _pick = (keys, source) => { - const result = {} - - for (let i = 0, length = keys.length; i < length; i++) { - const key = keys[i] - const value = source[key] +/** + * @param {string} key Field name to extract values from + * @param {object[]} source Array of objects + * + * @returns {Array} + */ +const _pick = (key, source) => { + const result = [] - if (Object.hasOwnProperty.call(source, key)) { - result[key] = value - } + for (let i = 0, length = source.length; i < length; i++) { + result.push(source[i][key]) } return result } /** - * Returns a partial copy of an object containing only the keys specified. - * If the key does not exist, the property is ignored. + * Returns a new list by extracting the same named property off all objects in + * the source list * - * @tag Object - * @signature ( keys: string[] ) => ( source: Object ): Object + * @param {...any} params * - * @param {string[]} keys The properties to be filtered out - * @param {object} source The source object + * @returns {Array} * - * @returns {object} + * @tag Array + * @signature (key: string) => (source: object[]): mixed[] * * @example - * pick(["id", "name"])({id: 2, name: "lorem", description: "lorem ipsum"}) - * // => {id: 2, name: lorem} + * pick("position")([{id: 1, position: 3}, {id:2, position: -1}]) + * // => [3, -1] */ -export const pick = curry(_pick) +export const pick = (...params) => { + // @signature (key) => (source) + if (params.length <= 1) { + return source => _pick(params[0], source) + } + + // @signature (key, source) + return _pick(...params) +} diff --git a/src/pick/pick.test.js b/src/pick/pick.test.js index 1c95b06..cc8bb7e 100644 --- a/src/pick/pick.test.js +++ b/src/pick/pick.test.js @@ -3,24 +3,25 @@ import test from "tape" import { pick } from "./pick" test("pick", t => { - const source = { - lorem: "ipsum", - dolor: "amet", - } + const source = [ + { + id: 1, + position: 3, + onlyHere: 1, + }, + { + id: 2, + position: -1, + }, + ] - t.deepEqual( - pick(["dolor", "lorem"])(source), - { lorem: "ipsum", dolor: "amet" }, - "All existing keys" - ) + t.deepEqual(pick("position")(source), [3, -1], "Array with extracted field") t.deepEqual( - pick(["lorem", "not-exist"])(source), - { lorem: "ipsum" }, - "Some non-existing keys" + pick("onlyHere", source), + [1, undefined], + "Array with extracted field not available in all source elements" ) - t.deepEqual(pick(["not-exist"])(source), {}, "All non-existing keys") - t.end() }) diff --git a/src/pluck/pluck.js b/src/pluck/pluck.js index 847a247..a8fad13 100644 --- a/src/pluck/pluck.js +++ b/src/pluck/pluck.js @@ -1,29 +1,65 @@ -import { curry } from "../curry/curry" +import { map } from "../map/map" -const _pluck = (field, source) => { - const result = [] +/** + * @param {string[]} keys The properties to be filtered out + * @param {object} source The source object + * + * @returns {object} + */ +const _pluckOne = (keys, source) => { + const result = {} - for (let i = 0, length = source.length; i < length; i++) { - result.push(source[i][field]) + for (let i = 0, length = keys.length; i < length; i++) { + const key = keys[i] + const value = source[key] + + if (Object.hasOwnProperty.call(source, key)) { + result[key] = value + } } return result } /** - * Returns a new list by extracting the same named property off all objects in - * the source list + * @param {string[]} keys + * @param {object|object[]} source * - * @param {string} field Field name to extract values from - * @param {object[]} source Array of objects + * @returns {object|object[]} + */ +const _pluck = (keys, source) => + Array.isArray(source) + ? map(item => _pluckOne(keys, item), source) + : _pluckOne(keys, source) + +/** + * Returns a partial copy of an object containing only the keys specified. + * If the key does not exist, the property is ignored. + * + * @param {...any} params * - * @returns {number} + * @returns {object|object[]} * - * @tag Array - * @signature ( field: string ) => ( source: Object[] ): mixed[] + * @tag Object + * @signature (keys: string[]) => (source: Object): Object * * @example - * pluck("position")([{id: 1, position: 3}, {id:2, position: -1}]) - * // => [3, -1] + * pluck( + * ["id", "name"], + * { + * id: 2, + * name: "lorem", + * description: "lorem ipsum" + * } + * ) + * // => {id: 2, name: lorem} */ -export const pluck = curry(_pluck) +export const pluck = (...params) => { + // @signature (keys) => (source) + if (params.length <= 1) { + return source => _pluck(params[0], source) + } + + // @signature (keys, source) + return _pluck(...params) +} diff --git a/src/pluck/pluck.test.js b/src/pluck/pluck.test.js index 301308e..6fe0378 100644 --- a/src/pluck/pluck.test.js +++ b/src/pluck/pluck.test.js @@ -3,24 +3,58 @@ import test from "tape" import { pluck } from "./pluck" test("pluck", t => { - const source = [ - { - id: 1, - position: 3, - onlyHere: 1, - }, - { - id: 2, - position: -1, - }, - ] + t.deepEqual( + pluck(["dolor", "lorem"])({ + lorem: "ipsum", + dolor: "amet", + }), + { lorem: "ipsum", dolor: "amet" }, + "Plucking existing keys should return trimmed object (curried)" + ) + + t.deepEqual( + pluck(["dolor", "lorem"], { + lorem: "ipsum", + dolor: "amet", + }), + { lorem: "ipsum", dolor: "amet" }, + "Plucking existing keys should return trimmed object (uncurried)" + ) - t.deepEqual(pluck("position")(source), [3, -1], "Array with extracted field") + t.deepEqual( + pluck(["lorem", "not-exist"], { + lorem: "ipsum", + dolor: "amet", + }), + { lorem: "ipsum" }, + "Some non-existing keys" + ) + + t.deepEqual( + pluck(["not-exist"], { + lorem: "ipsum", + dolor: "amet", + }), + {}, + "All non-existing keys" + ) t.deepEqual( - pluck("onlyHere", source), - [1, undefined], - "Array with extracted field not available in all source elements" + pluck( + ["id"], + [ + { + id: "ipsum", + title: "amet", + }, + { + id: "lorem", + title: "amet", + }, + ] + ), + [{ id: "ipsum" }, { id: "lorem" }], + "Plucking existing keys should return trimmed object (uncurried)" ) t.end()