[![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) {
        //
    }

