synthet1c
synthet1c

Reputation: 6282

ramda reshape object structure from base object

I'm sure it's possible to take an object and modify it and filter it to get another shape for easier consumption after an api request, but unfortunately I'm not able to create any elegant solutions that don't involve using path and prop for every key eg.

const { prop, path } = R

const baseObject = {
  id: 1,
  name: 'object-one',
  info: {
   items: [
      { name: 'item-one', url: '/images/item-one.jpg' },
    ]
  },
}

const newObj = {
  id: prop('id', baseObject),
  name: prop('name', baseObject),
  // image is a new prop not found on the base object
  image: path(['info', 'items', 0, 'url'], baseObject),
}

console.log(newObj)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
<script src="https://codepen.io/synthet1c/pen/KyQQmL.js"></script>

Can anyone show me if there is a way to do elegant pointfree object reshaping. It seems like there should be some mapper function that can take the base object as a seed, but I can't seem to pinpoint it.

I have tried evolve but that doesn't add new points, I have tried lens but I may have missed something from the documentation because I can only modify existing keys or filter down like with prop.

Cheers,

edit. I was able to create a mapping function that will do the job, but is there a better way?

const { prop, path, toUpper, map, compose } = R

const baseObject = {
  id: 1,
  name: 'object-one',
  info: {
   items: [
      { name: 'item-one', url: '/images/item-one.jpg' },
    ]
  },
}
// createObjectFromSpec :: { k: f(a) } -> a -> { k: b }
const createObjectFromSpec = spec => baseObj => R.map(f => f(baseObj), spec);
const createObjectTypeOne = createObjectFromSpec({
  id: prop('id'),
  name: prop('name'),
  // image is a new prop not found on the base object
  image: path(['info', 'items', 0, 'url']),
})

const createObjectTypeTwo = createObjectFromSpec({
  id: prop('id'),
  name: prop('name'),
  // image is a new prop not found on the base object
  itemName: path(['info', 'items', 0, 'name']),
})

console.log(
  createObjectTypeOne(baseObject)
)

console.log(
  createObjectTypeTwo(baseObject)
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
<script src="https://codepen.io/synthet1c/pen/KyQQmL.js"></script>

Upvotes: 2

Views: 174

Answers (1)

Scott Christopher
Scott Christopher

Reputation: 6516

The createObjectFromSpec function you have in your example exists in Ramda as applySpec.

const fn = R.applySpec({
  id: R.prop('id'),
  name: R.prop('name'),
  image: R.path(['info', 'items', 0, 'url'])
})

const result = fn({
  id: 1,
  name: 'object-one',
  info: {
   items: [
      { name: 'item-one', url: '/images/item-one.jpg' },
    ]
  },
})

console.log(result)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

Upvotes: 4

Related Questions