UNPKG

@themost/jspa

Version:
623 lines (461 loc) 17 kB
[![npm](https://img.shields.io/npm/v/@themost%2Fjspa.svg)](https://www.npmjs.com/package/@themost%2Fjspa) ![GitHub top language](https://img.shields.io/github/languages/top/themost-framework/jspa) [![License](https://img.shields.io/npm/l/@themost/jspa)](https://github.com/themost-framework/jspa/blob/master/LICENSE) ![GitHub last commit](https://img.shields.io/github/last-commit/themost-framework/jspa) ![GitHub Release Date](https://img.shields.io/github/release-date/themost-framework/jspa) [![npm](https://img.shields.io/npm/dw/@themost/jspa)](https://www.npmjs.com/package/@themost%2Fjspa) ![Snyk Vulnerabilities for npm package](https://img.shields.io/snyk/vulnerabilities/npm/@themost/jspa) ![MOST Web Framework Logo](https://github.com/themost-framework/common/raw/master/docs/img/themost_framework_v3_128.png) # @themost/jspa [@themost web framework](https://github.com/themost-framework) JavaScript Persistent API on top of [@themost/data](https://github.com/themost-framework/data) ORM. `@themost/jspa` is a mimic of Java Persistent API for Node.js environment and provides a set of tools for describing object relational mapping. The following example describes a `Thing` class: import { DataObject } from '@themost/data'; import { Column, Entity, GeneratedValue, GenerationType, Id, Table, Counter, Basic, Formula, ManyToOne, FetchType, ColumnDefault } from '@themost/jspa'; @Entity() @Table() class Thing extends DataObject { constructor() { super(); } @Id() @Column() @GeneratedValue({ strategy: GenerationType.Identity }) public id?: Counter; @Basic() public name?: string; @Column() public alternateName?: string; @Column() public description?: string; @Column() public additionalType?: string; @Column() public sameAs?: string; @Column() public url?: string; @Column() public identifier?: string; @Column() public image?: string; @Column({ nullable: false, updatable: false }) @ColumnDefault(() => new Date()) public dateCreated?: Date; @Column({ nullable: false }) @Formula(() => new Date()) public dateModified?: Date; @Column({ nullable: true, updatable: false, type: 'User' }) @ManyToOne({ fetchType: FetchType.Lazy }) public createdBy?: any; @Column({ nullable: true, type: 'User' }) @ManyToOne({ fetchType: FetchType.Lazy }) public modifiedBy?: any; } export { Thing } ## Usage npm i @themost/jspa ## Annotations ### @Entity The basic annotation of a class. Use optional `@Entity.name` attribute to define the name of this entity if it's different than class name and `@Entity.version` attribute to allow `@themost/data` auto-upgrade operations to update database objects after any change. @Entity({ version: '1.0.0' }) class Party extends Thing { ... } `@Entity()` annotation includes `@Entity.privileges` attribute to allow setting the collection of default privileges assigned to a class @Entity({ version: '1.0.0', privileges: [ { mask: 15, type: 'global' }, { mask: 15, type: 'global', account: 'Administrators' } ] }) class Party extends Thing { ... } The previous example defines that `Party` will be accessible by each user which has permissions defined in data permission storage. It also defines that `Administrators` have full-access by default. ### @Table The optional @Table annotation allows you to specify the properties of the database objects that will be used to persist the entity in the database. @Entity({ version: '1.0.0' }) @Table( name: 'PartyBase' ) class Party extends Thing { ... } - @Table.name The name of the table that will be used to persist objects. The default value provided by `@themost/data` is a concatenation of entity's name and word "Base" e.g. `PartyBase`, `PostalAddressBase` etc. - @Table.indexes A collection of indexes that should be included while creating or updating database objects. @Table( indexes: [ { columnList: [ 'name' ] }, { columnList: [ 'email' ] } ] ) class Party extends Thing { ... } - @Table.uniqueConstraints A collection of unique constraints that should be included while creating or updating database objects based on database engine features. @Table( uniqueConstraints: [ { columnNames: [ 'email' ] } ] ) class Party extends Thing { ... } ### @Column `@Column` annotation is used to specify the mapped column for a property @Entity() @Table() class Thing extends DataObject { ... @Column() public name?: string; } - @Column.name (Optional) A string which defines the column name. If `@Column.name` is missing property name is being used. class Thing extends DataObject { ... @Column({ name: 'obj_name' }) public name?: string; } - @Column.nullable (Optional) A boolean which indicates whether the mapped column is nullable of false. The default value is true. - @Column.type A string which defines the type of the column. Column may be one of the primitive column types of `@themost/data` or an object type class Thing extends DataObject { ... @Column({ type: ColumnType.Text }) public name; @Column({ type: 'User' }) public createdBy; } - @Column.length (Optional) The column length class Thing extends DataObject { ... @Column({ type: ColumnType.Text, length: 100 }) public name; } - @Column.scale (Optional) The scale for a numeric column - @Column.precision (Optional) The precision for a numeric column - @Column.insertable (Optional) A boolean which indicates whether the column will be included while inserting objects or not - @Column.updatable (Optional) A boolean which indicates whether the column will be included while updating objects or not ### @Id() `@Id` is used to specify identity columns @Entity() @Table() class Thing extends DataObject { @Id() @Column({ type: ColumnType.Counter }) @GeneratedValue({ strategy: GenerationType.Identity }) public id; ... } ### @GeneratedValue() `@GeneratedValue` annotation is used to specify generation strategy for identity columns @Entity() @Table() class Thing extends DataObject { @Id() @Column({ type: ColumnType.Counter }) @GeneratedValue({ strategy: GenerationType.Identity }) public id; ... } The available generation strategies are: - `GenerationType.Auto`: Based on the database’s support for primary key generation framework decides which generator type to be used. - `GenerationType.Identity`: In this case database is responsible for determining and assigning the next primary key. - `GenerationType.Sequence`: A sequence specify a database object that can be used as a source of primary key values. - `GenerationType.Table`: It keeps a separate table with the primary key values ### @Formula `@Formula` annotation is used to specify calculated values. class Thing extends DataObject { ... @Formula((event) => { const context = event.context as any; let user: { name?: string } =context.interactiveUser; if (user && user.name) { return { name: user.name }; } user = context.user; if (user && user.name) { return { name: user.name }; } return null; }) public createdBy?: any; } `@Formula` closure has `event` parameter of type `FormulaArgs` - `FormulaArgs.context` The current data context - `Formula.model` An instance of `DataModel` class which represents the current entity type - `Formula.target` The current object ### @ColumnDefault `@ColumnDefault` annotation defines the default value of the mapped column @Entity() @Table() class Thing extends DataObject { ... @ColumnDefault(() => new Date()) public dateCreated?: Date; } `@ColumnDefault` can be a simple closure which returns a single value or a closure which has `event` parameter of type `ColumnDefaultArgs` - `ColumnDefaultArgs.context` The current data context - `ColumnDefaultArgs.model` An instance of `DataModel` class which represents the current entity type - `ColumnDefaultArgs.target` The current object ### @Embedded `@Embedded` annotation is used to embed type into another type. An embedded type will be inserted, updated or deleted as result of an operation made on parent object. @Entity() class Place extends Thing { ... @Embedded() public address?: PostalAddress; } e.g. `Place` entity type embeds `PostalAddress` into `address` property. ### @ManyToOne `@ManyToOne` annotation defined a foreign-key association between two entity types @Entity() class Party extends Thing { ... @Column({ nullable: false, updatable: false, type: 'User' }) @ManyToOne({ fetchType: FetchType.Lazy }) public createdBy?: User; } e.g. `Party.createdBy` defines a foreign-key association between `Party` and `User` - `@ManyToOne.optional` A boolean which whether the association is optional or not. - `@ManyToOne.fetchType` Defines that data can be lazily or eagerly fetched ### @OneToMany `@OneToMany` annotation is used to implement one-to-many relationship between two entity types. @Entity() class Place extends Thing { ... @OneToMany({ cascadeType: CascadeType.Detach, fetchType: FetchType.Lazy, mappedBy: 'containedIn', targetEntity: 'Place' }) public containsPlace?: Place; } e.g. `Place` has a collection of places based on property `containedIn` `@OneToMany` annotation has the following properties - `@ManyToOne.fetchType` Defines that data can be lazily or eagerly fetched - `@ManyToOne.cascadeType` Defines the cascade operation that will be used while removing an object. - `@ManyToOne.mappedBy` The target column that holds the association between the current entity type and the target entity type. - `@ManyToOne.targetEntity` The type of the target entity ### @ManyToMany `@OneToMany` annotation is used to implement many-to-many relationship between two entity types. class Group extends Account { ... @ManyToMany({ targetEntity: 'Account', fetchType: FetchType.Lazy, cascadeType: CascadeType.Detach }) @JoinTable({ name: 'GroupMembers', joinColumns: [ { name: 'object', referencedColumnName: 'id' } ], inverseJoinColumns: [ { name: 'value', referencedColumnName: 'id' } ] }) public members?: Account[]; ... } e.g. Every `Group` has a collection of `members` of type `Account` `@ManyToOne` annotation has the following properties - `@ManyToOne.fetchType` Defines that data can be lazily or eagerly fetched - `@ManyToOne.cascadeType` Defines the cascade operation that will be used while removing an object. - `@ManyToOne.targetEntity` The type of the target entity The `@JoinTable` annotation is being used to define the database object where this relationship will be stored. `@JoinTable.joinColumns` contains the local property and `@JoinTable.inverseJoinColumns` contains the foreign property. e.g. `Group.members` many-to-many association will be stored in `GroupMembers` table where `GroupMembers.object` column will be a `Group.id` and `GroupMembers.value` column will be an `Account.id`. ### @ElementCollection `@ElementCollection` annotation is used to define a collection of primitive typed values e.g. an array of strings or numbers. class Account extends Thing { ... @ManyToMany({ targetClass: Text, fetchType: FetchType.Lazy }) @CollectionTable({ name: 'AccountTags', joinColumns: [ { name: 'object', referencedColumnName: 'id' } ], inverseJoinColumns: [ { name: 'value' } ] }) tags; ... } e.g. Every `Account` has a collection of `tags` of type `Text` which is a subclass of `String` The `@CollectionTable` annotation is being used to define the database object where this relationship will be stored. `@CollectionTable.joinColumns` contains the local property and `@CollectionTable.inverseJoinColumns` may contain the column where each value will be stored. e.g. `Account.tags` will be persisted in `AccountTags` table where `object` field contains `Account.id` and `value` field contains `Account.tag` value. ### @EntityListeners `@EntityListeners` annotation defines a collection of classes that contain procedures which are going to be executed before and after CRUD operations. @Entity() @EntityListeners(OnUserUpdateListener, OnUserRemoveListener, OnUserInitListener) class User extends Account { ... } e.g. `OnUserUpdateListener` contains `PreUpdate` and `PostUpdate` procedures export class OnUserUpdateListener { @PreUpdate() async onPreUpdate(event: PreUpdateEvent) { // } @PostUpdate() async onPostUpdate(event: PostUpdateEvent) { // } } ### @PreInit `@PreInit` annotation defines an event which will be occured before creating or updating an entity type @PreInit() async onPreInit(event: PreInitEvent) { // } ### @PostInit `@PostInit` annotation defines an event which will be occured after creating or updating an entity type @PostInit() async onPostInit(event: PostInitEvent) { // } ### @PreLoad `@PreLoad` annotation defines an event which will be occured before loading an entity @PreLoad() async onPreLoad(event: PreLoadEvent) { // } ### @PostLoad `@PostInit` annotation defines an event which will be occured after loading an entity @PostLoad() async onPostLoad(event: PostLoadEvent) { // } ### @PrePersist `@PreLoad` annotation defines an event which will be occured before inserting an entity @PrePersist() async onPrePersist(event: PrePersistEvent) { // } ### @PostPersist `@PostPersist` annotation defines an event which will be occured after inserting an entity @PostPersist() async onPostPersist(event: PostPersistEvent) { // } ### @PreUpdate `@PreUpdate` annotation defines an event which will be occured before updating an entity @PreUpdate() async onPreUpdate(event: PreUpdateEvent) { // } ### @PostUpdate `@PostUpdate` annotation defines an event which will be occured after updating an entity @PostUpdate() async onPostUpdate(event: PostUpdateEvent) { // } ### @PreRemove `@PreRemove` annotation defines an event which will be occured before removing an entity @PreRemove() async onPreRemove(event: PreRemoveEvent) { // } ### @PostUpdate `@PostRemove` annotation defines an event which will be occured after removing an entity @PostRemove() async onPostRemove(event: PostRemoveEvent) { // }