{"id":20604788,"url":"https://github.com/themost-framework/jspa","last_synced_at":"2025-08-31T11:42:52.979Z","repository":{"id":61050572,"uuid":"446062651","full_name":"themost-framework/jspa","owner":"themost-framework","description":"JavaScript Persistent API","archived":false,"fork":false,"pushed_at":"2025-01-14T14:45:11.000Z","size":301,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-14T16:08:52.152Z","etag":null,"topics":["api","data","database-schema","jspa","object-relational-mapping","orm","orm-framework"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/themost-framework.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-01-09T10:59:57.000Z","updated_at":"2025-01-14T14:44:42.000Z","dependencies_parsed_at":"2023-02-12T09:31:07.259Z","dependency_job_id":null,"html_url":"https://github.com/themost-framework/jspa","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/themost-framework%2Fjspa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/themost-framework%2Fjspa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/themost-framework%2Fjspa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/themost-framework%2Fjspa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/themost-framework","download_url":"https://codeload.github.com/themost-framework/jspa/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234300457,"owners_count":18810610,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","data","database-schema","jspa","object-relational-mapping","orm","orm-framework"],"created_at":"2024-11-16T09:24:50.580Z","updated_at":"2025-01-17T02:15:23.308Z","avatar_url":"https://github.com/themost-framework.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![npm](https://img.shields.io/npm/v/@themost%2Fjspa.svg)](https://www.npmjs.com/package/@themost%2Fjspa)\n![GitHub top language](https://img.shields.io/github/languages/top/themost-framework/jspa)\n[![License](https://img.shields.io/npm/l/@themost/jspa)](https://github.com/themost-framework/jspa/blob/master/LICENSE)\n![GitHub last commit](https://img.shields.io/github/last-commit/themost-framework/jspa)\n![GitHub Release Date](https://img.shields.io/github/release-date/themost-framework/jspa)\n[![npm](https://img.shields.io/npm/dw/@themost/jspa)](https://www.npmjs.com/package/@themost%2Fjspa)\n![Snyk Vulnerabilities for npm package](https://img.shields.io/snyk/vulnerabilities/npm/@themost/jspa)\n\n![MOST Web Framework Logo](https://github.com/themost-framework/common/raw/master/docs/img/themost_framework_v3_128.png)\n\n# @themost/jspa\n[@themost web framework](https://github.com/themost-framework) JavaScript Persistent API on top of [@themost/data](https://github.com/themost-framework/data) ORM.\n\n`@themost/jspa` is a mimic of Java Persistent API for Node.js environment and provides a set of tools for describing object relational mapping.\n\nThe following example describes a `Thing` class:\n\n    import { DataObject } from '@themost/data';\n    import { Column, Entity, GeneratedValue, GenerationType, Id, Table, Counter, Basic, Formula, ManyToOne, FetchType, ColumnDefault } from '@themost/jspa';\n\n    @Entity()\n    @Table()\n    class Thing extends DataObject {\n\n        constructor() {\n            super();\n        }\n\n        @Id()\n        @Column()\n        @GeneratedValue({\n            strategy: GenerationType.Identity\n        })\n        public id?: Counter;\n\n        @Basic()\n        public name?: string;\n\n        @Column()\n        public alternateName?: string;\n\n        @Column()\n        public description?: string;\n\n        @Column()\n        public additionalType?: string;\n\n        @Column()\n        public sameAs?: string;\n\n        @Column()\n        public url?: string;\n\n        @Column()\n        public identifier?: string;\n\n        @Column()\n        public image?: string;\n\n        @Column({\n            nullable: false,\n            updatable: false\n        })\n        @ColumnDefault(() =\u003e new Date())\n        public dateCreated?: Date;\n\n        @Column({\n            nullable: false\n        })\n        @Formula(() =\u003e new Date())\n        public dateModified?: Date;\n\n        @Column({\n            nullable: true,\n            updatable: false,\n            type: 'User'\n        })\n        @ManyToOne({\n            fetchType: FetchType.Lazy\n        })\n        public createdBy?: any;\n\n        @Column({\n            nullable: true,\n            type: 'User'\n        })\n        @ManyToOne({\n            fetchType: FetchType.Lazy\n        })\n        public modifiedBy?: any;\n    }\n\n    export {\n        Thing\n    }\n\n## Usage\n\n    npm i @themost/jspa\n\n## Annotations\n\n### @Entity\n\nThe 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.\n\n    @Entity({\n        version: '1.0.0'\n    })\n    class Party extends Thing {\n        ...\n    }\n\n`@Entity()` annotation includes `@Entity.privileges` attribute to allow setting the collection of default privileges assigned to a class\n\n    @Entity({\n        version: '1.0.0',\n        privileges: [\n            {\n                mask: 15,\n                type: 'global'\n            },\n            {\n                mask: 15,\n                type: 'global',\n                account: 'Administrators'\n            }\n        ]\n    })\n    class Party extends Thing {\n        ...\n    }\n\nThe 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.\n\n### @Table\n\nThe optional @Table annotation allows you to specify the properties of the database objects that will be used to persist the entity in the database. \n\n    @Entity({\n        version: '1.0.0'\n    })\n    @Table(\n        name: 'PartyBase'\n    )\n    class Party extends Thing {\n        ...\n    }\n\n- @Table.name\n\n    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.\n\n- @Table.indexes\n\n    A collection of indexes that should be included while creating or updating database objects.\n\n        @Table(\n            indexes: [\n                {\n                    columnList: [\n                        'name'\n                    ]\n                },\n                {\n                    columnList: [\n                        'email'\n                    ]\n                }\n            ]\n        )\n        class Party extends Thing {\n            ...\n        }\n\n- @Table.uniqueConstraints\n\n    A collection of unique constraints that should be included while creating or updating database objects based on database engine features.\n\n        @Table(\n            uniqueConstraints: [\n                {\n                    columnNames: [\n                        'email'\n                    ]\n                }\n            ]\n        )\n        class Party extends Thing {\n            ...\n        }\n\n### @Column\n\n`@Column` annotation is used to specify the mapped column for a property\n\n    @Entity()\n    @Table()\n    class Thing extends DataObject {\n        ...\n        @Column()\n        public name?: string;\n    }\n\n- @Column.name \n\n    (Optional) A string which defines the column name. If `@Column.name` is missing property name is being used.\n\n        class Thing extends DataObject {\n            ...\n            @Column({\n                name: 'obj_name'\n            })\n            public name?: string;\n        }\n\n- @Column.nullable \n\n    (Optional) A boolean which indicates whether the mapped column is nullable of false. The default value is true.\n\n- @Column.type\n\n    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\n\n        class Thing extends DataObject {\n            ...\n            @Column({\n                type: ColumnType.Text\n            })\n            public name;\n\n            @Column({\n                type: 'User'\n            })\n            public createdBy;\n        }\n\n- @Column.length\n\n    (Optional) The column length\n\n        class Thing extends DataObject {\n            ...\n            @Column({\n                type: ColumnType.Text,\n                length: 100\n            })\n            public name;\n        }\n\n- @Column.scale\n\n    (Optional) The scale for a numeric column\n\n- @Column.precision\n\n    (Optional) The precision for a numeric column\n\n- @Column.insertable\n\n    (Optional) A boolean which indicates whether the column will be included while inserting objects or not\n\n- @Column.updatable\n\n    (Optional) A boolean which indicates whether the column will be included while updating objects or not\n\n### @Id()\n\n`@Id` is used to specify identity columns\n\n    @Entity()\n    @Table()\n    class Thing extends DataObject {\n        \n        @Id()\n        @Column({\n            type: ColumnType.Counter\n        })\n        @GeneratedValue({\n            strategy: GenerationType.Identity\n        })\n        public id;\n        ...\n    }\n\n### @GeneratedValue()\n\n`@GeneratedValue` annotation is used to specify generation strategy for identity columns\n\n    @Entity()\n    @Table()\n    class Thing extends DataObject {\n        \n        @Id()\n        @Column({\n            type: ColumnType.Counter\n        })\n        @GeneratedValue({\n            strategy: GenerationType.Identity\n        })\n        public id;\n        ...\n    }\n\nThe available generation strategies are:\n\n- `GenerationType.Auto`: Based on the database’s support for primary key generation framework decides which generator type to be used.\n\n- `GenerationType.Identity`: In this case database is responsible for determining and assigning the next primary key.\n\n- `GenerationType.Sequence`: A sequence specify a database object that can be used as a source of primary key values.\n\n- `GenerationType.Table`: It keeps a separate table with the primary key values\n\n### @Formula\n\n`@Formula` annotation is used to specify calculated values.\n\n    class Thing extends DataObject {\n\n        ...\n        @Formula((event) =\u003e {\n            const context = event.context as any;\n            let user: { name?: string } =context.interactiveUser;\n            if (user \u0026\u0026 user.name) {\n                return {\n                    name: user.name\n                };\n            }\n            user = context.user;\n            if (user \u0026\u0026 user.name) {\n                return {\n                    name: user.name\n                };\n            }\n            return null;\n        })\n        public createdBy?: any;\n\n    }\n\n`@Formula` closure has `event` parameter of type `FormulaArgs`\n\n- `FormulaArgs.context` The current data context\n\n- `Formula.model` An instance of `DataModel` class which represents the current entity type\n\n- `Formula.target` The current object\n\n### @ColumnDefault\n\n`@ColumnDefault` annotation defines the default value of the mapped column\n\n    @Entity()\n    @Table()\n    class Thing extends DataObject {\n        ...\n        @ColumnDefault(() =\u003e new Date())\n        public dateCreated?: Date;\n    }\n\n`@ColumnDefault` can be a simple closure which returns a single value or a closure which has `event` parameter of type `ColumnDefaultArgs`\n\n- `ColumnDefaultArgs.context` The current data context\n\n- `ColumnDefaultArgs.model` An instance of `DataModel` class which represents the current entity type\n\n- `ColumnDefaultArgs.target` The current object\n\n### @Embedded\n\n`@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.\n\n    @Entity()\n    class Place extends Thing {\n        ...\n        @Embedded()\n        public address?: PostalAddress;\n    }\n\ne.g. `Place` entity type embeds `PostalAddress` into `address` property.\n\n### @ManyToOne\n\n`@ManyToOne` annotation defined a foreign-key association between two entity types\n\n    @Entity()\n    class Party extends Thing {\n\n        ...\n        @Column({\n            nullable: false,\n            updatable: false,\n            type: 'User'\n        })\n        @ManyToOne({\n            fetchType: FetchType.Lazy\n        })\n        public createdBy?: User;\n    }\n\n\ne.g. `Party.createdBy` defines a foreign-key association between `Party` and `User`\n\n- `@ManyToOne.optional` A boolean which whether the association is optional or not.\n- `@ManyToOne.fetchType` Defines that data can be lazily or eagerly fetched\n\n### @OneToMany\n\n`@OneToMany` annotation is used to implement one-to-many relationship between two entity types.\n\n    @Entity()\n    class Place extends Thing {\n\n        ...\n        @OneToMany({\n            cascadeType: CascadeType.Detach,\n            fetchType: FetchType.Lazy,\n            mappedBy: 'containedIn',\n            targetEntity: 'Place'\n        })\n        public containsPlace?: Place;\n\n    }\n\ne.g. `Place` has a collection of places based on property `containedIn`\n\n`@OneToMany` annotation has the following properties\n\n- `@ManyToOne.fetchType` Defines that data can be lazily or eagerly fetched\n- `@ManyToOne.cascadeType` Defines the cascade operation that will be used while removing an object.\n- `@ManyToOne.mappedBy` The target column that holds the association between the current entity type and the target entity type.\n- `@ManyToOne.targetEntity` The type of the target entity\n\n### @ManyToMany\n\n`@OneToMany` annotation is used to implement many-to-many relationship between two entity types.\n\n    class Group extends Account {\n        ...\n        @ManyToMany({\n            targetEntity: 'Account',\n            fetchType: FetchType.Lazy,\n            cascadeType: CascadeType.Detach\n        })\n        @JoinTable({\n            name: 'GroupMembers',\n            joinColumns: [\n                {\n                    name: 'object',\n                    referencedColumnName: 'id'\n                }\n            ],\n            inverseJoinColumns: [\n                {\n                    name: 'value',\n                    referencedColumnName: 'id'\n                }\n            ]\n        })\n        public members?: Account[];\n        ...\n    }\ne.g. Every `Group` has a collection of `members` of type `Account`\n\n\n`@ManyToOne` annotation has the following properties\n\n- `@ManyToOne.fetchType` Defines that data can be lazily or eagerly fetched\n- `@ManyToOne.cascadeType` Defines the cascade operation that will be used while removing an object.\n- `@ManyToOne.targetEntity` The type of the target entity\n\nThe `@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.\n\ne.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`.\n\n### @ElementCollection\n\n`@ElementCollection` annotation is used to define a collection of primitive typed values e.g. an array of strings or numbers.\n\n    class Account extends Thing {\n        ...\n        @ManyToMany({\n            targetClass: Text,\n            fetchType: FetchType.Lazy\n        })\n        @CollectionTable({\n            name: 'AccountTags',\n            joinColumns: [\n                {\n                    name: 'object',\n                    referencedColumnName: 'id'\n                }\n            ],\n            inverseJoinColumns: [\n                {\n                    name: 'value'\n                }\n            ]\n        })\n        tags;\n        ...\n    }\ne.g. Every `Account` has a collection of `tags` of type `Text` which is a subclass of `String`\n\nThe `@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.\n\ne.g. `Account.tags` will be persisted in `AccountTags` table where `object` field contains `Account.id` and `value` field contains `Account.tag` value.\n\n### @EntityListeners\n\n`@EntityListeners` annotation defines a collection of classes that contain procedures which are going to be executed before and after CRUD operations.\n\n    @Entity()\n    @EntityListeners(OnUserUpdateListener, OnUserRemoveListener, OnUserInitListener)\n    class User extends Account {\n        ...\n    }\n\ne.g. `OnUserUpdateListener` contains `PreUpdate` and `PostUpdate` procedures\n\n    export class OnUserUpdateListener {\n        @PreUpdate()\n        async onPreUpdate(event: PreUpdateEvent) {\n            //\n        }\n        @PostUpdate()\n        async onPostUpdate(event: PostUpdateEvent) {\n            //\n        }\n    }\n\n### @PreInit\n\n`@PreInit` annotation defines an event which will be occured before creating or updating an entity type\n\n    @PreInit()\n    async onPreInit(event: PreInitEvent) {\n        //\n    }\n\n### @PostInit \n\n`@PostInit` annotation defines an event which will be occured after creating or updating an entity type\n\n    @PostInit()\n    async onPostInit(event: PostInitEvent) {\n        //\n    }\n\n### @PreLoad\n\n`@PreLoad` annotation defines an event which will be occured before loading an entity\n\n    @PreLoad()\n    async onPreLoad(event: PreLoadEvent) {\n        //\n    }\n\n### @PostLoad\n\n`@PostInit` annotation defines an event which will be occured after loading an entity\n\n    @PostLoad()\n    async onPostLoad(event: PostLoadEvent) {\n        //\n    }\n\n### @PrePersist\n\n`@PreLoad` annotation defines an event which will be occured before inserting an entity\n\n    @PrePersist()\n    async onPrePersist(event: PrePersistEvent) {\n        //\n    }\n\n### @PostPersist\n\n`@PostPersist` annotation defines an event which will be occured after inserting an entity\n\n    @PostPersist()\n    async onPostPersist(event: PostPersistEvent) {\n        //\n    }\n\n### @PreUpdate\n\n`@PreUpdate` annotation defines an event which will be occured before updating an entity\n\n    @PreUpdate()\n    async onPreUpdate(event: PreUpdateEvent) {\n        //\n    }\n\n### @PostUpdate\n\n`@PostUpdate` annotation defines an event which will be occured after updating an entity\n\n    @PostUpdate()\n    async onPostUpdate(event: PostUpdateEvent) {\n        //\n    }\n\n### @PreRemove\n\n`@PreRemove` annotation defines an event which will be occured before removing an entity\n\n    @PreRemove()\n    async onPreRemove(event: PreRemoveEvent) {\n        //\n    }\n\n### @PostUpdate\n\n`@PostRemove` annotation defines an event which will be occured after removing an entity\n\n    @PostRemove()\n    async onPostRemove(event: PostRemoveEvent) {\n        //\n    }\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthemost-framework%2Fjspa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthemost-framework%2Fjspa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthemost-framework%2Fjspa/lists"}