Git Product home page Git Product logo

fast-mapper's Introduction

๐Ÿ”— fast-mapper

A simple JIT & @decorator based object mapper

fast-mapper makes it easy to map classes to plain objects and back using @decorators.

Why? Because solutions like class-transformer are verrrryyy slow when hydrating a lot of documents, and we want to do better... so use this instead!

Features

  • Extremely simply @Decorator() based document mapping
  • Very fast ๐Ÿš€! (thanks to JIT compilation)
  • Discriminator mapping
  • & more!

Planned Features

  • Validation
  • Create more common types
  • Figure out what else should be added

How to use

import { Property, map } from 'fast-mapper';
import { ObjectId } from 'mongodb';

abstract class Base {
  @Property({ type: ObjectIdType })
  _id: ObjectId;

  get id(): string {
    return this._id.toHexString();
  }

  @Property()
  createdAt: Date = new Date();

  @Property()
  updatedAt: Date = new Date();
}

Now create our document class with some fields.

import { Property } from 'fast-mapper';
import { BaseDocument, Address, Pet } from './models';

class User extends Base {
  @Property()
  name: string;

  @Property(() => Address)
  address: Address; // single embedded document

  @Property(() => [Address])
  addresses: Address[] = []; // array of embedded documents

  @Property(() => [Pet])
  pets: Pet[] = []; // array of discriminator mapped documents

  @Property(() => Pet)
  favoritePet: Pet; // single discriminator mapped document
  
  @Property({ type: 'date' }) // "type" needs to be specified here due to reflection not seeing the Date[] since it's an array.
  dates: Date[];
}

and here's the nested Address document.

import { Property } from 'fast-mapper';

class Address {
  @Property()
  city: string;

  @Property()
  state: string;
}

Now let's do some mapping...

import { map } from 'fast-mapper';
import { User } from './models';

const user = new User();
user.name = 'John Doe';
// ... populate the rest


/**
 * Plain mapping (converts to destination mapping, including names)
 */

// converting to the mapped value as a plain object
const plain = map(User).toPlain(user);

// .. and convert back
const user = map(User).fromPlain(plain);


/**
 * JSON mapping (keeps original property names)
 */

// convert to a JSON compatible type (useful for micro-service communication as an example)
const json = map(User).toJSON(user);

// .. and convert back
const user = map(User).fromJSON(json);


/**
 * Instance Property Mapping (keeps original property names)
 */

// Alternatively, you can create a user via mapping:
const user = map(User).fromProps({ name: 'John Doe', /* ... */ });

// and if you want to convert a user to it's props (unmapped field names)
const props = map(User).toProps(user);

Property Types

Types can be automatically discovered using reflection (reflect-metadata) and the Type.prototype.isType property, however, if your property is an array, you must specify the type manually using @Property({ type: 'date' }) dates: Date[] otherwise the values will not be mapped.

You can also create a custom type that extends Type (See types/DateType as an example).

To register your custom type, see the example below (these are also in tests/__fixtures__).

registerType(new ObjectIdType());
registerType(new UUIDType());

Discriminator Mapping

fast-mapper also has support for discriminator mapping (polymorphism). You do this by creating a base class mapped by @Discriminator({ property: '...' }) with a @Property() with the name of the "property". Then decorate discriminator types with @Discriminator({ value: '...' }) and fast-mapper takes care of the rest.

import { Discriminator, Property } from 'fast-mapper';

@Discriminator({ property: 'type' })
abstract class Pet {
  @Property()
  abstract type: string;

  @Property()
  abstract sound: string;

  speak(): string {
    return this.sound;
  }
}

@Discriminator({ value: 'dog' })
class Dog extends Pet {
  type: string = 'dog';
  sound: string = 'ruff';

  // dog specific fields & methods
}

@Discriminator({ value: 'cat' })
class Cat extends Pet {
  type: string = 'cat';
  sound: string = 'meow';

  // cat specific fields & methods
}

And now, lets see the magic!

import { map } from 'fast-mapper';
import { User } from './models';

async () => {
  const user = map(User).create({
    name: 'John Doe',
    address: {
      city: 'San Diego',
      state: 'CA'
    },
    addresses: [
      {
        city: 'San Diego',
        state: 'CA'
      }
    ],
    pets: [{ type: 'dog', sound: 'ruff' }],
    favoritePet: { type: 'dog', sound: 'ruff' }
  });
  
  console.log(user instanceof User); // true

  const mapped = map(User).toPlain(user);

  console.log(user instanceof User); // false
};

Want to use this in a library / ORM?

We wanted to make sure to keep library and user-land mapping separated, so consuming libraries can have their own mapping and type registration separate from a user's.

All you have to do to add mapping to your library is:

import { Mapper } from 'fast-mapper';

const mapper = new Mapper();

function Field(/* your options */): PropertyDecorator {
  return (target: any, propertyName: string) => {
    mapper.decorators.Property(/* map your options to Property options */)(target, propertyName);
  }
}

Examples

For more advanced usage and examples, check out the tests.

fast-mapper's People

Contributors

j avatar

Stargazers

 avatar

Watchers

 avatar

fast-mapper's Issues

Architecture and Benchmarks

Can you provide some information on how this achieves faster mapping in comparison to other frameworks?

Also some benchmarks would be good. I could add this if you can get back to me with an architecture overview.

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.