Skip to content

Commit

Permalink
feat: Switch logic of "pluck" and "pick". Update "pluck" to accept ob…
Browse files Browse the repository at this point in the history
…ject 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.
  • Loading branch information
andreidmt committed Dec 3, 2020
1 parent 33d1ab9 commit 13fea23
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 65 deletions.
48 changes: 27 additions & 21 deletions src/pick/pick.js
Original file line number Diff line number Diff line change
@@ -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)
}
29 changes: 15 additions & 14 deletions src/pick/pick.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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()
})
66 changes: 51 additions & 15 deletions src/pluck/pluck.js
Original file line number Diff line number Diff line change
@@ -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)
}
64 changes: 49 additions & 15 deletions src/pluck/pluck.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down

0 comments on commit 13fea23

Please sign in to comment.