0.1.7 • Published 7 years ago

lemon-js v0.1.7

Weekly downloads
2
License
MIT
Repository
github
Last release
7 years ago

Build Status NPM version Dependencies status Coverage Status

Installation

Install with npm:

npm i -S lemon-js

Usage

Define models

import { TypedModel, model, property } from 'lemon-js';

@model
export class Permission extends TypedModel {
	@property public name: string;
}

@model
export class User extends TypedModel {
	@property public age: number;
	@property({ index: true }) public email: string;
	// Use either ref or refer.
	@property([{ refer: Permission }]) public permissions: [Permission];
	@property({ default: false }) public isActive: boolean;
	@property({ unique: true }) public name: string;

	public get displayName() {
		return `${ this.name } <${ this.email }>`;
	}

	public static findByEmail(email: string): Query<User> {
		return this.findOne({ email });
	}
}

@model
export class Post extends TypedModel {
	@property public title: string;
	@property public body: string;
	@property({ default: 0 }) public readCount: number;
	@property public creator: User;

	public static findByTitle(title: string): Query<Post> {
		return this.findOne({ title });
	}
}

@model
export class TypedUser extends User {
	@property({ default: 'user' }) public type: string;
}

Insert objects

const write = new Permission({
	name: 'write'
});
await write.save();

const read = new Permission({
	name: 'read'
});
await read.save();

const user = new User({
	age: 20,
	email: 'user1@example.com',
	name: 'User 1',
	permissions: [read._id, write._id]
});
await user.save();

const post = new Post({
	body: 'Post body',
	creator: user._id,
	title: 'Post 1',
});
await post.save();

Retrieve objects

const post = await Post.findByTitle('Post 1').populate('creator').exec();
expect(post.title).to.be.equal('Post 1');
expect(post.creator.displayName).to.be.equal('User 1 <user1@example.com>');

const user = await User.findByEmail('user1@example.com').populate('permissions').exec();
expect(user.name).to.be.equal('User 1');
expect(user.permissions.length).to.be.equal(2);
expect(user.permissions[0].name).to.be.equal('read');
expect(user.permissions[1].name).to.be.equal('write');

Sub-document

Model

export interface IColor {
	r: number;
	g: number;
	b: number;
}

export interface ICar {
	make: string;
	model: string;
	color: IColor;
	users?: User[];
}

export interface IRoom {
	color: IColor;
	name: string;
	owner: User;
	windows: IWindow[];
	computer: IComputer;
}

export interface IWindow {
	color: IColor;
	installer: User;
}

export interface IComputer {
	color: IColor;
	users: User[];
}

export interface IHouse {
	name: string;
	car: ICar;
	rooms: IRoom[];
}

@model
export class House extends TypedModel implements IHouse {
	@property name: string;

	@property({
		subdoc: true,
		make: String,
		model: String,
		color: {
			r: Number,
			g: Number,
			b: Number
		},
		users: [{ ref: User }]
	})
	car: ICar;

	@property([{
		subdoc: true,
		name: String,
		color: {
			r: Number,
			g: Number,
			b: Number
		},
		owner: { refer: User },
		windows: [{
			// Nested subdoc
			subdoc: true,
			installer: { ref: User }
		}],
		computer: {
			// Nested subdoc
			subdoc: true,
			users: [{ ref: User }]
		}
	}])
	rooms: IRoom[];
}

Insert a sub-document

const wife = new User({
	age: 20,
	email: 'user1@example.com',
	name: 'Wife',
	permissions: []
});
await wife.save();

const husband = new User({
	age: 25,
	email: 'user2@example.com',
	name: 'Husband',
	permissions: []
});
await husband.save();

const house = new House({
	name: 'home',
	car: {
		make: 'BMW',
		model: '550i',
		color: {
			r: 255,
			g: 20,
			b: 20
		},
		users: [wife._id, husband._id]
	},
	rooms: [{
		name: 'bedroom 1',
		color: {
			r: 20,
			g: 255,
			b: 20
		},
		owner: wife._id
	}, {
		name: 'bedroom 2',
		color: {
			r: 20,
			g: 20,
			b: 255
		},
		owner: husband._id
	}]
});
await house.save();

Populate a subdocument

const house: House = await House.findOne({ name: 'home' }).populate('rooms.owner').exec() as House;
const house: House = await House.findOne({ name: 'home' }).populate('car.users').exec() as House;

Middlewares (pre & post hooks)

@method({
	pre: ['save'],
	post: ['remove']
})
public preSavePostRemove() {
}

Validations

@model
export class ValidateTest extends TypedModel {
	public static EMAIL_REGEX = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;

	@property({
		validate: [ValidateTest.validateEmail1, 'Uh oh, "{PATH}" invalid 1.']
	})
	public email1: string;
	@property({
		validate: [{
			validator: ValidateTest.validateEmail2_1,
			message: 'Uh oh, "{PATH}" invalid 2-1.'
		}, {
			validator: ValidateTest.validateEmail2_2,
			message: 'Uh oh, "{PATH}" invalid 2-2.'
		}]
	})
	public email2: string;
	@property({
		validate: ValidateTest.validateEmail3
	})
	public email3: string;
	@property({
		validate: {
			isAsync: true,
			validator: ValidateTest.validateEmail4,
			message: 'Uh oh, "{PATH}" invalid 4.'
		}
	})
	public email4: string;

	public static validateEmail1(value) {
		// Object is mapped to object
		return ValidateTest.EMAIL_REGEX.test(value);
	}

	public static validateEmail2_1(value) {
		// Object is mapped to object
		return value.length > 2;
	}

	public static validateEmail2_2(value) {
		// Object is mapped to object
		return ValidateTest.EMAIL_REGEX.test(value);
	}

	public static validateEmail3(value) {
		// Object is mapped to object
		return ValidateTest.EMAIL_REGEX.test(value);
	}

	public static validateEmail4(value, callback) {
		// Object is mapped to object
		// Support mongoose isAsync callback
		let result = ValidateTest.EMAIL_REGEX.test(value);
		callback(result, 'Overwriting error');
	}

	@method<ValidateTest>({
		validate: ['email2', 'email3'],
		message: 'Validating for both email2 and email3'
	})
	public validateEmail2AndEmail3(value, callback) {
		let result = ValidateTest.EMAIL_REGEX.test(value);
		callback(result, 'Overwriting error');
	}
}

createdAt & updatedAt

let user = await User.findOne({});

// Created date
let creationDate = user.createdAt;

// Updated date
let updateDate = user.updatedAt;

Hiding fields from toJSON() and toObject()

@model
export class House extends TypedModel implements IHouse {
	@property({
		hidden: true
	})
	name: string;

	@property({
		subdoc: true,
		hidden: ['make'],
		make: String,
		model: String,
		color: {
			r: Number,
			g: Number,
			b: Number
		},
		users: [{ ref: User }]
	})
	car: ICar;

	@property([{
		subdoc: { autoIndex: false },
		hidden: ['owner'],
		name: String,
		color: {
			hidden: ['r'],
			r: Number,
			g: Number,
			b: Number
		},
		owner: { refer: User },
		windows: [{
			hidden: true,
			subdoc: true,
			installer: { ref: User }
		}],
		computer: {
			hidden: ['users'],
			subdoc: true,
			users: [{ ref: User }],
			system: String,
			color: {
				r: Number,
				g: Number,
				b: Number
			}
		}
	}])
	rooms: IRoom[];
}

You can overwrite this when you run toJSON or toObject with the following option (default false).

const house: House = await House.findOne({ name: 'home' }).populate('rooms.computer').exec() as House;
const json = house.toJSON({
	showHidden: true
})

License

Licensed under MIT.

Credits

Based on the work of @megahertz/mongoose-model

0.1.7

7 years ago

0.1.6

7 years ago

0.1.5

7 years ago

0.1.4

7 years ago

0.1.3

7 years ago

0.1.2

7 years ago

0.1.1

7 years ago

0.1.0

7 years ago

0.0.9

7 years ago

0.0.8

7 years ago

0.0.7

7 years ago

0.0.6

7 years ago

0.0.5

7 years ago

0.0.4

7 years ago

0.0.3

7 years ago

0.0.2

7 years ago

0.0.1

7 years ago