Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/themost-framework/jspa
JavaScript Persistent API
https://github.com/themost-framework/jspa
api data database-schema jspa object-relational-mapping orm orm-framework
Last synced: about 3 hours ago
JSON representation
JavaScript Persistent API
- Host: GitHub
- URL: https://github.com/themost-framework/jspa
- Owner: themost-framework
- License: bsd-3-clause
- Created: 2022-01-09T10:59:57.000Z (almost 3 years ago)
- Default Branch: main
- Last Pushed: 2023-01-29T20:06:32.000Z (almost 2 years ago)
- Last Synced: 2024-11-13T11:56:58.711Z (3 days ago)
- Topics: api, data, database-schema, jspa, object-relational-mapping, orm, orm-framework
- Language: TypeScript
- Homepage:
- Size: 481 KB
- Stars: 1
- Watchers: 2
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
[![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 entityThe `@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) {
//
}