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 CHANGED
@@ -1,4 +1,4 @@
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';
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.UUIDField = exports.Field = void 0;
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, "UUIDField", { enumerable: true, get: function () { return remult3_1.UUIDField; } });
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remult",
3
- "version": "0.9.25",
3
+ "version": "0.9.29",
4
4
  "description": "remult core lib",
5
5
  "homepage": "https://remult.dev/",
6
6
  "repository": {
package/readme.md CHANGED
@@ -1,13 +1,44 @@
1
1
  # Remult
2
2
  ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg) [![npm version](https://badge.fury.io/js/remult.svg)](https://badge.fury.io/js/remult)
3
3
 
4
- Remult is an unopinionated CRUD framework for fullstack TypeScript development.
4
+ ## What is Remult?
5
5
 
6
- ### Define Entity classes
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('Products', {
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
- ### Find and manipulate data in front end code...
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
- static increasePriceOfTofu(priceIncrease: number) {
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
- await product.save();
66
+ product.save();
28
67
  }
29
68
  ```
30
- ### ...*exactly* the same way as in back end code
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.repo(Product).findFirst({ name:'Tofu' });
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
- ### Secure the API with Fine-grained Authorization
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
- ## Remult handles the REST:
61
- * Secured back-end API endpoints for Entities and back-end methods
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>;
@@ -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 UUIDField<entityType = any, valueType = any>(...options: (FieldOptions<entityType, valueType> | ((options: FieldOptions<entityType, valueType>, remult: Remult) => void))[]): (target: any, key: any, c?: any) => void;
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 {