2.0.2 • Published 9 days ago

mapper-factory v2.0.2

Weekly downloads
-
License
ISC
Repository
github
Last release
9 days ago

Mapper-Factory

Mapper-Factory is a fully documented TypeScript library that provides a simple and easy-to-use way to map objects from one type to another. With just a few lines of code, you can convert complex, nested objects into the desired format.

Work well on data structure and after enjoy the coding process :)

Installation

To install the package, you can use npm by running the following command:

npm i mapper-factory

Or using yarn

yarn add mapper-factory

Problem to solve

We want to solve the problem to trasform a JSON object to a specific JS object adding custom properties, with integrated mapping. As example this JSON object:

{
  firstName: 'Rick',
  lastName: 'Sanchez',
  employees: [
    { firstName: 'Summer', lastName: 'Smith' },
    { firstName: 'Morty', lastName: 'Smith' }
  ],
  rolesToMap: [ 'CEO', 'EMPLOYEE' ],
  boss: { firstName: 'Jesus', lastName: 'Christ' }
}

must became a JS object:

User {
  name: 'Rick',
  surname: 'Sanchez',
  employees: [
    User { name: 'Summer', surname: 'Smith' },
    User { name: 'Morty', surname: 'Smith' }
  ],
  roles: [ 'CEO TEST TRASFORMER', 'EMPLOYEE TEST TRASFORMER' ],
  boss: User { name: 'Jesus', surname: 'Christ' }
  /** maybe some methods... */
}

Usage V2

Mapping simple objects

Your class must use MapClass decorator and set an interface that extends MapInterface In this way your class could extend another, but continue using intellisense methods for YourClass

@MapClass()
class YourClass extends YourCustomClassToExtend {
    /** YOUR PROPERTIES  */
}
interface YourClass extends MapInterface<YourClass> { }

To get new YourClass instance it's simple as always:

new YourClass();

but now you can easly mapping an object just using MapInterface method from:

const yourInstance: YourClass = new YourClass().from(/** YOUR OBJECT TO MAP HERE*/);

and reverse your mapping using using MapInterface method toMap:

const reversedMapping: Object = yourInstance.toMap();

With MapInterface you can use on your class instance also other methods:

  • from: Create a new instance using model to map
const yourInstance: YourClass = new YourClass().from(/** YOUR OBJECT TO MAP HERE */);
  • toMap: Create a JSON object using reverse mapping
const reverseMappedObject: Object = yourInstance.toMap();
  • toModel: Create a new instance using same model of final JS object
const anotherInstance: YourClass = new YourClass.toModel(yourInstance);
  • empty: Check if the object is empty
const isEmpty: boolean = yourInstance.empty();
  • filled: Check if the object is filled
const isFilled: boolean = yourInstance.filled();
  • get: Get specific property of the object
const specificProp: T = yourInstance.get('specificProp') as T;
  • set: Set specific property of the object
yourInstance.set('specificProp', /** NEW VALUE FOR 'specificProp' */);
  • copy: Deep copy of the object
const yourInstanceCopy: YourClass = yourInstance.copy();

After that, you can use @MapField decorator over single property to specify the mapping. Let's dive into an example:

@MapClass()
class User {

    @MapField({
        src: 'firstName'
    })
    name: string;

    @MapField({
        src: 'obj.obj[0][1]',
        transformer: (arr) => arr.map(role => role + " TEST TRASFORMER"),
        reverser: (arr) => arr.map(role => role.replace(" TEST TRASFORMER", "")),
    })
    roles?: string[];

    @MapField({
        transformer: (user) => new User(user)
    })
    boss: User;
}
interface User extends MapInterface<User> { }

Inside @MapField you can use:

  • src: define a string of original field name (also using a path like "obj.obj0")
  • transform: function to transform data input in constructor of the class
  • reverse: function to transform data input in toMap method of the class

In this example:

@MapClass()
class User {

    id: string;
    username: string;

    @MapField({
        src: 'firstName'
    })
    name: string;

    @MapField({
        src: 'lastName'
    })
    surname: string;

    @MapField({
        src: 'rolesToMap',
        transformer: (arr) => arr.map(role => role + " TEST TRASFORMER"),
        reverser: (arr) => arr.map(role => role.replace(" TEST TRASFORMER", "")),
    })
    roles?: string[];

    @MapField({
        transformer: (arr) => arr.map(user => new User(user))
    })
    employees?: User[];

    @MapField({
        transformer: (user) => new User(user)
    })
    boss?: User;
}
interface User extends MapInterface<User> { }

You can define a new User u, using two employees (using the same User model here but for a different object is the same):

let emp1: User = new User().from({ firstName: "Summer", lastName: "Smith" });
let emp2: User = new User().from({ firstName: "Morty", lastName: "Smith" });

let u = new User().from({ firstName: "Rick", lastName: "Sanchez", employees: [emp1.toMap(), emp2.toMap()], rolesToMap: ["CEO", "EMPLOYEE"] });

Usage V1

Mapping simple objects

Your class must extends MapperFactory

class User extends MapperFactory {
    ...
}

After that, you can use @MapField decorator over single property to specify the mapping:

class User extends MapperFactory {

    @MapField({
        src: 'firstName'
    })
    name: string;

    @MapField({
        src: 'obj.obj[0][1]',
        transformer: (arr) => arr.map(role => role + " TEST TRASFORMER"),
        reverser: (arr) => arr.map(role => role.replace(" TEST TRASFORMER", "")),
    })
    roles?: string[];

    @MapField({
        transformer: (user) => new User(user)
    })
    boss: User;
}

Inside @MapField you can use:

  • src: define a string of original field name (also using a path like "obj.obj0")
  • transform: function to transform data input in constructor of the class
  • reverse: function to transform data input in toMap method of the class

In this example:

class User extends MapperFactory {

    id: string;
    username: string;

    @MapField({
        src: 'firstName'
    })
    name: string;

    @MapField({
        src: 'lastName'
    })
    surname: string;

    @MapField({
        src: 'rolesToMap',
        transformer: (arr) => arr.map(role => role + " TEST TRASFORMER"),
        reverser: (arr) => arr.map(role => role.replace(" TEST TRASFORMER", "")),
    })
    roles?: string[];

    @MapField({
        transformer: (arr) => arr.map(user => new User(user))
    })
    employees?: User[];

    @MapField({
        transformer: (user) => new User(user)
    })
    boss: User;
}

You can define a new User u:

let emp1: User = new User({ firstName: "Summer", lastName: "Smith" });
let emp2: User = new User({ firstName: "Morty", lastName: "Smith" });

let u = new User({ firstName: "Rick", lastName: "Sanchez", employees: [emp1, emp2], rolesToMap: ["CEO", "EMPLOYEE"] });

In that way you can create a new JS Object User passing a JSON object. Automatically constructor use src and transformer to obtain the correct object you want.

In the specific case considered we have trasformed a JSON object:

{
  firstName: 'Rick',
  lastName: 'Sanchez',
  employees: [
    { firstName: 'Summer', lastName: 'Smith' },
    { firstName: 'Morty', lastName: 'Smith' }
  ],
  rolesToMap: [ 'CEO', 'EMPLOYEE' ],
  boss: { firstName: 'Jesus', lastName: 'Christ' }
}

In this JS Object:

User {
  name: 'Rick',
  surname: 'Sanchez',
  employees: [
    User { name: 'Summer', surname: 'Smith' },
    User { name: 'Morty', surname: 'Smith' }
  ],
  roles: [ 'CEO TEST TRASFORMER', 'EMPLOYEE TEST TRASFORMER' ],
  boss: User { name: 'Jesus', surname: 'Christ' }
}

Just using the constructor of User class.

If you want to return to the original JSON Object you can just call toMap() method, in that way:

u.toMap()

Obtaining the original JSON Object.

You can also fill properties of an object from another (typically with same class) by using objToModel() method, in that way:

let uCopy = new User();
uCopy.objToModel(u);

This method is meant to be used also when you have a JSON object but in the correct format, for example:

let uCopy = new User();
uCopy.objToModel({ name: "Rick", surname: "Sanchez", employees: [emp1, emp2], roles: ["CEO", "EMPLOYEE"] })

Another utility method is empty() method, you can check if your object is empty or not in that way:

let user = new User();
user.empty(); //TRUE

user.name = "Rick";
user.empty(); //FALSE

It is implemented also a GET/SET method whitch use the path. Using get(path: string) and set(path: string, value: any) you can access to the property you want and then GET or SET the value:

u.set("name", "Rick TEST-SET");
console.log(u.get("name"));

With this mapper you can easily obtain a performant deep copy of your object doing:

let userDeepCopy = new User(u.toMap());

Functions

You can also use the following functions:

  • toMap(model: MapperFactory): Object: function to transform data input in toMap method of the class
  • toModel\(obj: Object): T: function to transform data input (JSON) in the specified model T
  • objToModel\(model: MapperFactory, obj: Object): T: T: function to get an instance of the object from a JSON representation without mapping it
  • copy\(model: MapperFactory): T: T: function to get an instance of the object from a JSON representation without mapping it
2.0.2

9 days ago

2.0.1

2 months ago

2.0.0

2 months ago

1.0.43

5 months ago

1.0.40

6 months ago

1.0.42

6 months ago

1.0.41

6 months ago

1.0.39

9 months ago

1.0.37

10 months ago

1.0.36

12 months ago

1.0.35

12 months ago

1.0.34

1 year ago

1.0.33

1 year ago

1.0.32

1 year ago

1.0.31

1 year ago

1.0.30

1 year ago

1.0.29

1 year ago

1.0.28

1 year ago

1.0.27

1 year ago

1.0.26

1 year ago

1.0.25

1 year ago

1.0.24

1 year ago

1.0.23

1 year ago

1.0.22

1 year ago

1.0.21

1 year ago

1.0.20

1 year ago

1.0.19

1 year ago

1.0.18

1 year ago

1.0.17

1 year ago

1.0.16

1 year ago

1.0.15

1 year ago

1.0.14

1 year ago

1.0.13

1 year ago

1.0.12

1 year ago

1.0.11

1 year ago

1.0.10

1 year ago

1.0.9

1 year ago

1.0.7

1 year ago

1.0.6

1 year ago

1.0.5

1 year ago

1.0.4

1 year ago

1.0.3

1 year ago

1.0.2

1 year ago

1.0.1

1 year ago

1.0.0

1 year ago