remult 0.9.25 → 0.9.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +1 -1
- package/index.js +2 -2
- package/package.json +1 -1
- package/readme.md +96 -34
- package/src/data-api.d.ts +1 -1
- package/src/data-interfaces.d.ts +4 -2
- package/src/remult3/RepositoryImplementation.d.ts +1 -1
- package/src/remult3/RepositoryImplementation.js +135 -142
- package/src/remult3/RepositoryImplementation.js.map +1 -1
- package/src/remult3/remult3.d.ts +3 -1
- package/src/server-action.js +14 -4
- package/src/server-action.js.map +1 -1
- package/valueConverters.js +1 -1
- package/valueConverters.js.map +1 -1
package/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { Field,
|
|
1
|
+
export { Field, UuidField, FieldsMetadata, Entity, EntityBase, ControllerBase, FieldRef, Fields, EntityMetadata, EntityOrderBy, EntityFilter, FindOptions, QueryResult, QueryOptions, Repository, FieldType, FindFirstOptions, ComparisonValueFilter, ValueFilter, ContainsStringValueFilter, getFields, EntityRef, getEntityRef, SortSegments, ValueListFieldType, DateOnlyField, JsonField, IntegerField, OmitEB, Paginator, CaptionTransformer } from './src/remult3';
|
|
2
2
|
export { EntityOptions } from './src/entity';
|
|
3
3
|
export { DataProvider, EntityDataProvider, EntityDataProviderFindOptions, ErrorInfo, RestDataProviderHttpProvider } from './src/data-interfaces';
|
|
4
4
|
export { SqlCommand, SqlImplementation, SqlResult } from './src/sql-command';
|
package/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Validators = exports.UrlBuilder = exports.FilterConsumerBridgeToSqlRequest = exports.Filter = exports.CompoundIdField = exports.OneToMany = exports.Sort = exports.IdEntity = exports.EventSource = exports.isBackend = exports.Remult = exports.Allow = exports.ProgressListener = exports.BackendMethod = exports.Controller = exports.JsonDataProvider = exports.SqlDatabase = exports.WebSqlDataProvider = exports.ArrayEntityDataProvider = exports.InMemoryDataProvider = exports.RestDataProvider = exports.CaptionTransformer = exports.IntegerField = exports.JsonField = exports.DateOnlyField = exports.ValueListFieldType = exports.getEntityRef = exports.getFields = exports.FieldType = exports.ControllerBase = exports.EntityBase = exports.Entity = exports.
|
|
3
|
+
exports.Validators = exports.UrlBuilder = exports.FilterConsumerBridgeToSqlRequest = exports.Filter = exports.CompoundIdField = exports.OneToMany = exports.Sort = exports.IdEntity = exports.EventSource = exports.isBackend = exports.Remult = exports.Allow = exports.ProgressListener = exports.BackendMethod = exports.Controller = exports.JsonDataProvider = exports.SqlDatabase = exports.WebSqlDataProvider = exports.ArrayEntityDataProvider = exports.InMemoryDataProvider = exports.RestDataProvider = exports.CaptionTransformer = exports.IntegerField = exports.JsonField = exports.DateOnlyField = exports.ValueListFieldType = exports.getEntityRef = exports.getFields = exports.FieldType = exports.ControllerBase = exports.EntityBase = exports.Entity = exports.UuidField = exports.Field = void 0;
|
|
4
4
|
/*
|
|
5
5
|
* Public API Surface of remult
|
|
6
6
|
*/
|
|
7
7
|
var remult3_1 = require("./src/remult3");
|
|
8
8
|
Object.defineProperty(exports, "Field", { enumerable: true, get: function () { return remult3_1.Field; } });
|
|
9
|
-
Object.defineProperty(exports, "
|
|
9
|
+
Object.defineProperty(exports, "UuidField", { enumerable: true, get: function () { return remult3_1.UuidField; } });
|
|
10
10
|
Object.defineProperty(exports, "Entity", { enumerable: true, get: function () { return remult3_1.Entity; } });
|
|
11
11
|
Object.defineProperty(exports, "EntityBase", { enumerable: true, get: function () { return remult3_1.EntityBase; } });
|
|
12
12
|
Object.defineProperty(exports, "ControllerBase", { enumerable: true, get: function () { return remult3_1.ControllerBase; } });
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -1,13 +1,44 @@
|
|
|
1
1
|
# Remult
|
|
2
2
|
 [](https://badge.fury.io/js/remult)
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
## What is Remult?
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
**Remult** is a fullstack CRUD framework which uses your TypeScript model types to provide:
|
|
7
|
+
|
|
8
|
+
* Secured REST API (highly configurable)
|
|
9
|
+
* Type-safe frontend API client
|
|
10
|
+
* Type-safe backend query builder
|
|
11
|
+
|
|
12
|
+
### Remult :heart: Monorepos
|
|
13
|
+
|
|
14
|
+
Using a `monorepo` approach, with model types shared between frontend and backend code, Remult can enforce data validation and constraints, defined once, on both frontend and REST API level.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
```sh
|
|
19
|
+
npm i remult
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Setup API backend using a Node.js Express middleware
|
|
23
|
+
```ts
|
|
24
|
+
import express from 'express';
|
|
25
|
+
import { remultExpress } from 'remult/remult-express';
|
|
26
|
+
|
|
27
|
+
const port = 3001;
|
|
28
|
+
const app = express();
|
|
29
|
+
|
|
30
|
+
app.use(remultExpress());
|
|
31
|
+
|
|
32
|
+
app.listen(port, () => {
|
|
33
|
+
console.log(`Example API listening at http://localhost:${port}`);
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Define model classes
|
|
7
38
|
```ts
|
|
8
39
|
import { Entity, EntityBase, Field } from 'remult';
|
|
9
40
|
|
|
10
|
-
@Entity('
|
|
41
|
+
@Entity('products', {
|
|
11
42
|
allowApiCrud: true
|
|
12
43
|
})
|
|
13
44
|
export class Product extends EntityBase {
|
|
@@ -18,27 +49,79 @@ export class Product extends EntityBase {
|
|
|
18
49
|
unitPrice: number = 0;
|
|
19
50
|
}
|
|
20
51
|
```
|
|
21
|
-
|
|
52
|
+
|
|
53
|
+
### :rocket: API Ready
|
|
54
|
+
```sh
|
|
55
|
+
> curl http://localhost:3001/api/products
|
|
56
|
+
|
|
57
|
+
[{"name":"Tofu","unitPrice":5}]
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Find and manipulate data in type-safe frontend code
|
|
22
61
|
```ts
|
|
23
|
-
|
|
24
|
-
const product = await remult.repo(Product).findFirst({ name:'Tofu' });
|
|
62
|
+
async function increasePriceOfTofu(priceIncrease: number) {
|
|
63
|
+
const product = await remult.repo(Product).findFirst({ name: 'Tofu' });
|
|
25
64
|
|
|
26
65
|
product.unitPrice += priceIncrease;
|
|
27
|
-
|
|
66
|
+
product.save();
|
|
28
67
|
}
|
|
29
68
|
```
|
|
30
|
-
|
|
69
|
+
|
|
70
|
+
### ...*exactly* the same way as in backend code
|
|
31
71
|
```ts
|
|
32
72
|
@BackendMethod({ allowed: Allow.authenticated })
|
|
33
|
-
static increasePriceOfTofu(priceIncrease: number, remult?: Remult) {
|
|
34
|
-
const product = await remult
|
|
73
|
+
static async increasePriceOfTofu(priceIncrease: number, remult?: Remult) {
|
|
74
|
+
const product = await remult!.repo(Product).findFirst({ name: 'Tofu' });
|
|
35
75
|
|
|
36
76
|
product.unitPrice += priceIncrease;
|
|
77
|
+
product.save();
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## :ballot_box_with_check: Data validation and constraints - defined once
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
import { Entity, EntityBase, Field } from 'remult';
|
|
85
|
+
import { Min } from 'class-validator';
|
|
86
|
+
|
|
87
|
+
@Entity('products', {
|
|
88
|
+
allowApiCrud: true
|
|
89
|
+
})
|
|
90
|
+
export class Product extends EntityBase {
|
|
91
|
+
@Field<Product>({
|
|
92
|
+
validate: p => {
|
|
93
|
+
if (p.name.trim().length == 0)
|
|
94
|
+
p.$.name.error = 'required';
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
name: string = '';
|
|
98
|
+
|
|
99
|
+
@Field()
|
|
100
|
+
@Min(0)
|
|
101
|
+
unitPrice: number = 0;
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Enforced in frontend:
|
|
106
|
+
```ts
|
|
107
|
+
const product = remult.repo(Product).create();
|
|
108
|
+
|
|
109
|
+
try {
|
|
37
110
|
await product.save();
|
|
38
111
|
}
|
|
112
|
+
catch {
|
|
113
|
+
console.error(product._.error); // Browser console will display - "Name: required"
|
|
114
|
+
}
|
|
39
115
|
```
|
|
40
116
|
|
|
41
|
-
###
|
|
117
|
+
### Enforced in backend:
|
|
118
|
+
```sh
|
|
119
|
+
> curl -d "{""unitPrice"":-1}" -H "Content-Type: application/json" -X POST http://localhost:3001/api/products
|
|
120
|
+
|
|
121
|
+
{"modelState":{"unitPrice":"unitPrice must not be less than 0","name":"required"},"message":"Name: required"}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## :lock: Secure the API with fine-grained authorization
|
|
42
125
|
```ts
|
|
43
126
|
@Entity<Article>('Articles', {
|
|
44
127
|
allowApiRead: true,
|
|
@@ -57,26 +140,5 @@ export class Article extends EntityBase {
|
|
|
57
140
|
}
|
|
58
141
|
```
|
|
59
142
|
|
|
60
|
-
##
|
|
61
|
-
|
|
62
|
-
* CRUD API requests (front end) / database commands (back end)
|
|
63
|
-
* Object-relational mapping
|
|
64
|
-
* Validations
|
|
65
|
-
* Caching
|
|
66
|
-
* Authorization
|
|
67
|
-
|
|
68
|
-
## Installation
|
|
69
|
-
```sh
|
|
70
|
-
npm i remult
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
## API Setup using Express
|
|
74
|
-
```ts
|
|
75
|
-
import * as express from 'express';
|
|
76
|
-
import { remultExpress } from 'remult/remult-express';
|
|
77
|
-
import 'entities';
|
|
78
|
-
|
|
79
|
-
let app = express();
|
|
80
|
-
app.use(remultExpress());
|
|
81
|
-
app.listen(3002, () => console.log("Server started"));
|
|
82
|
-
```
|
|
143
|
+
## Getting started
|
|
144
|
+
The best way to learn Remult is by following a tutorial of a simple fullstack Todo app using [React](https://remult.dev/tutorials/tutorial-react.html) or [Angular](https://remult.dev/tutorials/tutorial-angular.html).
|
package/src/data-api.d.ts
CHANGED
|
@@ -30,4 +30,4 @@ export interface DataApiRequest {
|
|
|
30
30
|
get(key: string): any;
|
|
31
31
|
}
|
|
32
32
|
export declare function determineSort(sortUrlParm: string, dirUrlParam: string): any;
|
|
33
|
-
export declare function serializeError(data: ErrorInfo): ErrorInfo
|
|
33
|
+
export declare function serializeError(data: ErrorInfo): ErrorInfo<any>;
|
package/src/data-interfaces.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Sort } from './sort';
|
|
2
2
|
import { Filter } from './filter/filter-interfaces';
|
|
3
|
-
import { EntityMetadata } from './remult3';
|
|
3
|
+
import { EntityMetadata, OmitEB } from './remult3';
|
|
4
4
|
export interface DataProvider {
|
|
5
5
|
getEntityDataProvider(entity: EntityMetadata): EntityDataProvider;
|
|
6
6
|
transaction(action: (dataProvider: DataProvider) => Promise<void>): Promise<void>;
|
|
@@ -26,10 +26,12 @@ export interface RestDataProviderHttpProvider {
|
|
|
26
26
|
get(url: string): Promise<any>;
|
|
27
27
|
}
|
|
28
28
|
export declare function extractSort(sort: any): Sort;
|
|
29
|
-
export interface ErrorInfo {
|
|
29
|
+
export interface ErrorInfo<entityType = any> {
|
|
30
30
|
message?: string;
|
|
31
31
|
modelState?: {
|
|
32
32
|
[key: string]: string;
|
|
33
|
+
} & {
|
|
34
|
+
[Properties in keyof Partial<OmitEB<entityType>>]?: string;
|
|
33
35
|
};
|
|
34
36
|
stack?: string;
|
|
35
37
|
exception?: any;
|
|
@@ -201,7 +201,7 @@ export declare function JsonField<entityType = any, valueType = any>(...options:
|
|
|
201
201
|
export declare function DateOnlyField<entityType = any>(...options: (FieldOptions<entityType, Date> | ((options: FieldOptions<entityType, Date>, remult: Remult) => void))[]): (target: any, key: any, c?: any) => void;
|
|
202
202
|
export declare function IntegerField<entityType = any>(...options: (FieldOptions<entityType, Number> | ((options: FieldOptions<entityType, Number>, remult: Remult) => void))[]): (target: any, key: any, c?: any) => void;
|
|
203
203
|
export declare function ValueListFieldType<entityType = any, valueType extends ValueListItem = any>(type: ClassType<valueType>, ...options: (FieldOptions<entityType, valueType> | ((options: FieldOptions<entityType, valueType>, remult: Remult) => void))[]): (target: any) => any;
|
|
204
|
-
export declare function
|
|
204
|
+
export declare function UuidField<entityType = any, valueType = any>(...options: (FieldOptions<entityType, valueType> | ((options: FieldOptions<entityType, valueType>, remult: Remult) => void))[]): (target: any, key: any, c?: any) => void;
|
|
205
205
|
export declare function Field<entityType = any, valueType = any>(...options: (FieldOptions<entityType, valueType> | ((options: FieldOptions<entityType, valueType>, remult: Remult) => void))[]): (target: any, key: any, c?: any) => void;
|
|
206
206
|
export declare function decorateColumnSettings<valueType>(settings: FieldOptions<any, valueType>, remult: Remult): FieldOptions<any, valueType>;
|
|
207
207
|
interface columnInfo {
|