Entity - Hookyns/unimapperjs GitHub Wiki
- async insert(entity: Entity)
- async remove(entity: Entity)
- async getAll() : Query
- async getById(id) : Entity
- select(...fields) : Object Creates new Object and copy selected fields
- async save() Save tracked changes
- mapFrom(data: Object) Map data from given Object into current entity instance.
Entity can be declared in two ways. Object-like and class-like.
It's simple declaration but it cannot have navigation properties, seeding nor additional methods.
const User = domain.createEntity("User", {
name: type.string.length(100),
email: type.string.length(100).unique(),
password: type.string.length(40),
created: type.date.now(),
deleted: type.boolean.default(false),
income: type.number.decimals(2).default(0)
});
Normal declaration by ES6 class which extends unimapperjs/src/Entity
.
TypeScript variant
import {type} from "unimapperjs";
import {Entity} from "unimapperjs/src/Entity";
import {domain} from "./domain";
import {Teacher} from "./Teacher";
@domain.entity() // decorator which registers this entity
export class Student extends Entity<Student>
{
/**
* Student Id
*/
id: number;
/**
* Student name
*/
name: string = "Can have default value defined like this one";
/**
* Student's teacher id
*/
teacherId: number;
/**
* Navigation property to Teacher
*/
teacher: Teacher;
// MAPPING
static map(map: Student) {
const {Teacher} = require("./Teacher");
map.id = <any>type.uuid;
map.name = <any>type.string.length(100);
map.teacherId = <any>type.number;
map.teacher = <any>type.foreign(Teacher.name)
.withForeign<Student>(s => s.teacherId); // Expression to property; allow refactoring
}
}
JavaScript variant
const {type} = require("unimapperjs");
const {Entity} = require("unimapperjs/src/Entity");
const {domain} = require("./domain");
const Teacher = class Teacher extends Entity {
constructor() {
super();
/**
* Teacher Id
* @type {number}
*/
this.id = null;
/**
* Teacher first name
* @type {string}
*/
this.firstName = null;
/**
* Teacher last name
* @type {string}
*/
this.lastName = null;
/**
* Teacher's students - navigation property
* @type {Promise<Array<Student>>}
*/
this.students = null;
}
static map(map) {
const { Student } = require("./Student");
map.id = type.number.primary().autoIncrement();
map.firstName = type.string.length(50);
map.lastName = type.string.length(50);
map.students = type.foreign(Student.name)
.hasMany(s => s.teacherId);
}
};
// Register entity with TS decorator function manually
domain.entity()(Teacher);
// export
module.exports.Teacher = Teacher;
You can omit constructor declaration, only map() method is important, but if you do so, you'll lose IDE completions.
Teacher navigate to Student and Student navigate to Teacher. There is cycle dependency which must be resolved. Method map() is async, it init map() method and rest of work is in process.nextTick, giving chance to node to resolve modules.
Because of that async behavior, you should not work with entities in same event-loop iteration in which you declare your entities.
See this example.
example.js
const {Student} = require("./Student");
// Create new Student
let newStudent = new Student();
newStudent.name = "John Smith";
Student.insert(newStudent);
If this is first time when Student is required, class Student in declared and domain.entity()(Student) will be called. But how I've said before, it is async and it's going to be finished in process.nextTick(). You can use setImmediate() for example, if you run some simple scripts, which has no async behavior, like this. But in most cases, after require() you wait eg. for connection, so it will not be necessary.
const $um = require("unimapperjs");
const MySqlAdapter = require(...);
const type = $um.type;
const domain = $um.createDomain(MySqlAdapter, "mysql://test:test@localhost/test");
/**
* Define User entity
* @class User
* @extends UniMapperEntity
*/
const User = domain.createEntity("User", {
name: type.string.length(100),
email: type.string.length(100).unique(),
password: type.string.length(40),
created: type.date.now(),
deleted: type.boolean.default(false),
income: type.number.decimals(2).default(0)
});
(async function() {
var user = new User({
name: "Jane",
email: "[email protected]",
password: "68d79gds4fv5sd4g645fgad6fg4"
};
await User.insert(user);
console.log("Insert ID:", user.id);
user.name = "Kate";
await user.save(); // Will create "update User SET name = 'Kate' where id = ...;" Only changed properties are sent
})().catch(function(err) {
console.error(err);
}).then(function() {
domain.dispose(); // End connection pool before exiting script
);