Coder Social home page Coder Social logo

michalzalecki / mappet Goto Github PK

View Code? Open in Web Editor NEW
51.0 5.0 4.0 1.33 MB

Lightweight, composable mappers for object transformations/normalization

Home Page: https://michalzalecki.github.io/mappet/

TypeScript 100.00%
transformations composable-mappers

mappet's Introduction

mappet

CircleCI

Lightweight, composable mappers for object transformations/normalization.


API Docs | Examples


Installation (npm)

npm i -S mappet

Use cases

  • Fault tolerant object transformations, no more Cannot read property of undefined.
  • Normalizing API responses shape and key names e.g. to camelCase or flattening nested payloads
  • Preparing nested API request payloads from flat form data
  • Filtering object entries e.g. omitting entries with undefined value
  • Per field modifications e.g. null to empty string to make React inputs happy

Examples

Basic

Simple value to value transformation

const schema = {
  firstName: "first_name",
  cardNumber: "card.number",
};
const mapper = mappet(schema);
const source = {
  first_name: "Michal",
  last_name: "Zalecki",
  card: {
    number: "5555-5555-5555-4444",
  },
};
const result = mapper(source);
// {
//   firstName: "Michal",
//   cardNumber: "5555-5555-5555-4444",
// }

Mapping values

Schema entries can be also option objects of path, modifier, and include. Modifier accepts selected value and original source object.

const formatDate = (date, source) => moment(date).format(source.country === "us" ? "MM/DD/YY" : "DD/MM/YY");
const upperCase = v => v.toUpperCase();

const schema = {
  country: { path: "country", modifier: upperCase },
  date: { path: "date", modifier: formatDate },
};
const mapper = mappet(schema);
const source = {
  country: "gb",
  date: "2016-07-30",
};
const result = mapper(source);
// {
//   country: "GB",
//   date: "30/07/16",
// }

Filtering entries

Using include you can control which values should be keept and what dropped.

const isGift = (value, source) => source.isGift;

const schema = {
  quantity: ["quantity"],
  message: { path: "giftMessage", include: isGift },
  remind_before_renewing: { path: "remindBeforeRenewingGift", include: isGift },
};
const mapper = mappet(schema);
const source = {
  quantity: 3,
  isGift: false,
  giftMessage: "All best!",
  remindBeforeRenewingGift: true,
};
const result = mapper(source);
// {
//   quantity: 3,
// };

Composing mappers

Mappers are just closures. It's easy to combine them using modifiers.

const userSchema = {
  firstName: "first_name",
  lastName: "last_name",
};
const userMapper = mappet(userSchema);

const usersSchema = {
  totalCount: "total_count",
  users: { path: "items", modifier: users => users.map(userMapper) },
};
const usersMapper = mappet(usersSchema);

const source = {
  total_count: 5,
  items: [
    { first_name: "Michal", last_name: "Zalecki" },
    { first_name: "John", last_name: "Doe" },
  ],
};
const result = usersMapper(source);
// {
//   totalCount: 5,
//   users: [
//     { firstName: "Michal", lastName: "Zalecki" },
//     { firstName: "John", lastName: "Doe" },
//   ],
// }

Strict mode

Mappers in strict mode will throw exception when value is not found on source object.

const schema = {
  firstName: "first_name",
  lastName: "last_name",
};
const mapper = mappet(schema, { strict: true });
const source = {
  first_name: "Michal",
};
const result = mapper(source);
// Uncaught Mappet: last_name not found

You can specify mapper name for easier debugging.

const userMapper = mappet(schema, { strictMode: true, name: "User Mapper" });
const user = mapper(source);
// Uncaught User Mapper: last_name not found

Greedy mode

Mappers in greedy mode will copy all properties from source object.

const schema = {
  last_name: { path: "last_name", modifier: str => str.toUpperCase() },
};
const mapper = mappet(schema, { greedy: true });
const source = {
  first_name: "Michal",
  last_name: "Zalecki",
  email: "[email protected]",
};
const actual = mapper(source);
// {
//   first_name: "Michal",
//   last_name: "ZALECKI",
//   email: "[email protected]",
// }

See tests for more examples.

mappet's People

Contributors

bytewiz avatar krzysztofkarol avatar michalzalecki avatar rkrupinski avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

mappet's Issues

Question: reverse a schema

is it possible to reverse the scheme for a mapper e.g.

Description

const source = {
   data: {
      entity: {
        key: 'someKey'
      },
      person: {
        firstname: 'someName'
      }
   }
}
const someMapper = mappet([
  ['key', 'data.entitiy.key'],
  ['name', 'data.person.firstname'],
])

result of someMapper(source)
{
  key: 'someKey'
  name: 'someName'
}

The "problem"

I want to reverse transform the object for it to send to the backend,
Is this possible without creating a scheme that is opposite with a function like:

someMapper(source, reverse)
or
reverse(someMapper(source))

I assume this is not part of the current API for this but just curious

[WIP] Support nested properties with dots

Current behavior:

const schema = {
  a: "a.b.c",
};
const mapper = mappet(schema);
const source = {
  "a": {
    "b.c": "value",
  },
};
const result = mapper(source);
// {
//   a: undefined,
// }

Expected behavior (compliant with lodash's get):

const schema = {
  a: { path: ["a", "b.c"] },
  // or less verbose
  // a: ["a", "b.c"],
};
const mapper = mappet(schema);
const source = {
  "a": {
    "b.c": "value",
  },
};
const result = mapper(source);
// {
//   a: "value",
// }

Consider importing lodash differently?

When checking the source code after having been notified by my build analyzer that lodash is required in this npm module.

I saw that lodash is imported like this: https://github.com/MichalZalecki/mappet/blob/master/src/lib/mappet.ts#L1

Which as far as I am aware this will include the entire lodash lib. (unless you have some sort of loader to cherry pick the functions for you)

Please correct me if I am wrong!

but according to the docs. from lodash it looks like they suggest importing like so aswell

image

before:

import { get, set, clone } from 'lodash';

after:

import get from 'lodash/get';
import set from 'lodash/set';
import clone from 'lodash/clone';

Thoughts one this? ๐Ÿ‘

If you agree, I can do a PR

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.