remult 0.13.20 → 0.13.23
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/package.json +2 -3
- package/readme.md +45 -30
- package/server/expressBridge.d.ts +5 -4
- package/server/expressBridge.js +10 -4
- package/server/register-actions-on-server.d.ts +2 -1
- package/server/register-actions-on-server.js +36 -4
- package/server/register-entities-on-server.d.ts +2 -1
- package/server/register-entities-on-server.js +4 -2
- package/src/data-providers/web-sql-data-provider.d.ts +1 -1
- package/src/data-providers/web-sql-data-provider.js +3 -2
- package/src/remult3/RepositoryImplementation.d.ts +6 -5
- package/src/remult3/RepositoryImplementation.js +36 -28
- package/src/remult3/remult3.d.ts +18 -13
- package/src/server-action.d.ts +1 -0
- package/src/server-action.js +8 -3
- package/src/shared-tests/entityWithValidations.js +5 -19
- package/src/tests/TestDataApiResponse.js +6 -6
- package/src/tests/d.d.ts +0 -1
- package/src/tests/d.js +0 -16
- package/src/tests/testModel/models.d.ts +0 -1
- package/src/tests/testModel/models.js +0 -3
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "remult",
|
|
3
|
-
"version": "0.13.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.13.23",
|
|
4
|
+
"description": "A CRUD framework for full-stack TypeScript",
|
|
5
5
|
"homepage": "https://remult.dev/",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"uuid": "^8.3.2",
|
|
16
|
-
"body-parser": "^1.18.3",
|
|
17
16
|
"reflect-metadata": "^0.1.13",
|
|
18
17
|
"tslib": "^2.3.1"
|
|
19
18
|
}
|
package/readme.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
</a>
|
|
5
5
|
<h1>Remult</h1>
|
|
6
6
|
<a href="https://circleci.com/gh/remult/remult/tree/master">
|
|
7
|
-
<img alt="CircleCI" src="https://circleci.com/gh/remult/remult/tree/master.svg?style=
|
|
7
|
+
<img alt="CircleCI" src="https://circleci.com/gh/remult/remult/tree/master.svg?style=shield">
|
|
8
8
|
</a>
|
|
9
9
|
<a href="https://codecov.io/gh/remult/remult">
|
|
10
10
|
<img src="https://codecov.io/gh/remult/remult/branch/master/graph/badge.svg?token=LYWQRUN3D1"/>
|
|
@@ -18,33 +18,36 @@
|
|
|
18
18
|
<a href="https://www.npmjs.com/package/remult">
|
|
19
19
|
<img alt="npm downloads" src="https://img.shields.io/npm/dm/remult">
|
|
20
20
|
</a>
|
|
21
|
-
<a href="https://
|
|
22
|
-
<img alt="
|
|
23
|
-
|
|
24
|
-
<a href="https://github.com/remult/remult/pulse" alt="Activity">
|
|
25
|
-
<img src="https://img.shields.io/github/commit-activity/m/remult/remult" /></a>
|
|
21
|
+
<a href="https://discord.gg/GXHk7ZfuG5">
|
|
22
|
+
<img alt="chat on discord" src="https://img.shields.io/badge/chat-on%20discord-blueviolet"/>
|
|
23
|
+
</a>
|
|
26
24
|
</div>
|
|
27
25
|
|
|
28
26
|
## What is Remult?
|
|
29
27
|
|
|
30
|
-
**Remult** is a
|
|
28
|
+
**Remult** is a full-stack CRUD framework that uses your TypeScript model types to provide:
|
|
31
29
|
|
|
32
30
|
* Secure REST API (highly configurable)
|
|
33
31
|
* Type-safe frontend API client
|
|
34
32
|
* Type-safe backend query builder
|
|
35
33
|
|
|
36
|
-
#### Remult :heart:
|
|
34
|
+
#### Remult :heart: Code Sharing
|
|
37
35
|
|
|
38
|
-
|
|
36
|
+
With model types shared between frontend and backend code, Remult can **enforce data validation and constraints, defined once, both in the front-end and witin back-end API routes**.
|
|
39
37
|
|
|
40
38
|
## Getting started
|
|
41
|
-
The best way to learn Remult is by following a tutorial of a simple Todo app with a Node.js Express backend.
|
|
39
|
+
The best way to learn Remult is by following a tutorial of a simple Todo web app with a Node.js Express backend.
|
|
40
|
+
|
|
41
|
+
* [Tutorial with React](https://remult.dev/tutorials/react/)
|
|
42
|
+
* [Tutorial with Angular](https://remult.dev/tutorials/angular/)
|
|
42
43
|
|
|
43
44
|
## Installation
|
|
44
45
|
```sh
|
|
45
46
|
npm i remult
|
|
46
47
|
```
|
|
47
48
|
|
|
49
|
+
## Usage
|
|
50
|
+
|
|
48
51
|
### Setup API backend using a Node.js Express middleware
|
|
49
52
|
```ts
|
|
50
53
|
import express from 'express';
|
|
@@ -60,14 +63,14 @@ app.listen(port, () => {
|
|
|
60
63
|
});
|
|
61
64
|
```
|
|
62
65
|
|
|
63
|
-
|
|
66
|
+
### Define model classes
|
|
64
67
|
```ts
|
|
65
|
-
import { Entity,
|
|
68
|
+
import { Entity, Fields } from 'remult';
|
|
66
69
|
|
|
67
70
|
@Entity('products', {
|
|
68
71
|
allowApiCrud: true
|
|
69
72
|
})
|
|
70
|
-
export class Product
|
|
73
|
+
export class Product {
|
|
71
74
|
@Fields.string()
|
|
72
75
|
name = '';
|
|
73
76
|
|
|
@@ -83,13 +86,14 @@ export class Product extends EntityBase {
|
|
|
83
86
|
[{"name":"Tofu","unitPrice":5}]
|
|
84
87
|
```
|
|
85
88
|
|
|
86
|
-
|
|
89
|
+
### Find and manipulate data in type-safe frontend code
|
|
87
90
|
```ts
|
|
88
91
|
async function increasePriceOfTofu(priceIncrease: number) {
|
|
89
|
-
const
|
|
92
|
+
const productsRepo = remult.repo(Product);
|
|
90
93
|
|
|
94
|
+
const product = await productsRepo.findFirst({ name: 'Tofu' });
|
|
91
95
|
product.unitPrice += priceIncrease;
|
|
92
|
-
|
|
96
|
+
productsRepo.save(product);
|
|
93
97
|
}
|
|
94
98
|
```
|
|
95
99
|
|
|
@@ -97,26 +101,27 @@ async function increasePriceOfTofu(priceIncrease: number) {
|
|
|
97
101
|
```ts
|
|
98
102
|
@BackendMethod({ allowed: Allow.authenticated })
|
|
99
103
|
static async increasePriceOfTofu(priceIncrease: number, remult?: Remult) {
|
|
100
|
-
const
|
|
104
|
+
const productsRepo = remult!.repo(Product);
|
|
101
105
|
|
|
106
|
+
const product = await productsRepo.findFirst({ name: 'Tofu' });
|
|
102
107
|
product.unitPrice += priceIncrease;
|
|
103
|
-
|
|
108
|
+
productsRepo.save(product);
|
|
104
109
|
}
|
|
105
110
|
```
|
|
106
111
|
|
|
107
|
-
|
|
112
|
+
### :ballot_box_with_check: Data validation and constraints - defined once
|
|
108
113
|
|
|
109
114
|
```ts
|
|
110
|
-
import { Entity,
|
|
115
|
+
import { Entity, Fields } from 'remult';
|
|
111
116
|
|
|
112
117
|
@Entity('products', {
|
|
113
118
|
allowApiCrud: true
|
|
114
119
|
})
|
|
115
|
-
export class Product
|
|
120
|
+
export class Product {
|
|
116
121
|
@Fields.string<Product>({
|
|
117
122
|
validate: product => {
|
|
118
123
|
if (product.name.trim().length == 0)
|
|
119
|
-
|
|
124
|
+
throw 'required';
|
|
120
125
|
}
|
|
121
126
|
})
|
|
122
127
|
name = '';
|
|
@@ -124,7 +129,7 @@ export class Product extends EntityBase {
|
|
|
124
129
|
@Fields.number({
|
|
125
130
|
validate: (_, field) => {
|
|
126
131
|
if (field.value < 0)
|
|
127
|
-
|
|
132
|
+
throw "must not be less than 0";
|
|
128
133
|
}
|
|
129
134
|
})
|
|
130
135
|
unitPrice = 0;
|
|
@@ -133,31 +138,31 @@ export class Product extends EntityBase {
|
|
|
133
138
|
|
|
134
139
|
### Enforced in frontend:
|
|
135
140
|
```ts
|
|
136
|
-
const product =
|
|
141
|
+
const product = productsRepo.create();
|
|
137
142
|
|
|
138
143
|
try {
|
|
139
|
-
await
|
|
144
|
+
await productsRepo.save(product);
|
|
140
145
|
}
|
|
141
|
-
catch {
|
|
142
|
-
console.error(
|
|
146
|
+
catch (e: any) {
|
|
147
|
+
console.error(e.message); // Browser console will display - "Name: required"
|
|
143
148
|
}
|
|
144
149
|
```
|
|
145
150
|
|
|
146
151
|
### Enforced in backend:
|
|
147
152
|
```sh
|
|
148
|
-
> curl
|
|
153
|
+
> curl http://localhost:3001/api/products -H "Content-Type: application/json" -d "{""unitPrice"":-1}"
|
|
149
154
|
|
|
150
155
|
{"modelState":{"unitPrice":"must not be less than 0","name":"required"},"message":"Name: required"}
|
|
151
156
|
```
|
|
152
157
|
|
|
153
|
-
|
|
158
|
+
### :lock: Secure the API with fine-grained authorization
|
|
154
159
|
```ts
|
|
155
160
|
@Entity<Article>('Articles', {
|
|
156
161
|
allowApiRead: true,
|
|
157
162
|
allowApiInsert: remult => remult.authenticated(),
|
|
158
163
|
allowApiUpdate: (remult, article) => article.author.id == remult.user.id
|
|
159
164
|
})
|
|
160
|
-
export class Article
|
|
165
|
+
export class Article {
|
|
161
166
|
@Fields.string({ allowApiUpdate: false })
|
|
162
167
|
slug = '';
|
|
163
168
|
|
|
@@ -168,3 +173,13 @@ export class Article extends EntityBase {
|
|
|
168
173
|
content = '';
|
|
169
174
|
}
|
|
170
175
|
```
|
|
176
|
+
|
|
177
|
+
## Example App
|
|
178
|
+
|
|
179
|
+
[CRM demo](https://github.com/remult/crm-demo) with a React + [MUI](https://mui.com) front-end and Postgres database.
|
|
180
|
+
|
|
181
|
+
## Contributing
|
|
182
|
+
Contributions are welcome. See [CONTRIBUTING](CONTRIBUTING.md).
|
|
183
|
+
|
|
184
|
+
## License
|
|
185
|
+
Remult is [MIT Licensed](LICENSE).
|
|
@@ -6,10 +6,10 @@ import { DataApi, DataApiRequest, DataApiResponse } from '../src/data-api';
|
|
|
6
6
|
import { AllowedForInstance } from '../src/context';
|
|
7
7
|
import { ClassType } from '../classType';
|
|
8
8
|
export declare function remultExpress(options?: {
|
|
9
|
-
/**
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
/** Sets a database connection for Remult.
|
|
10
|
+
*
|
|
11
|
+
* @see [Connecting to a Database](https://remult.dev/docs/databases.html).
|
|
12
|
+
*/
|
|
13
13
|
dataProvider?: DataProvider | Promise<DataProvider> | (() => Promise<DataProvider | undefined>);
|
|
14
14
|
bodySizeLimit?: string;
|
|
15
15
|
disableAutoApi?: boolean;
|
|
@@ -20,6 +20,7 @@ export declare function remultExpress(options?: {
|
|
|
20
20
|
defaultGetLimit?: number;
|
|
21
21
|
entities?: ClassType<any>[];
|
|
22
22
|
controllers?: ClassType<any>[];
|
|
23
|
+
bodyParser?: boolean;
|
|
23
24
|
}): RemultExpressBridge;
|
|
24
25
|
export interface RemultExpressBridge extends express.RequestHandler {
|
|
25
26
|
getRemult(req: express.Request): Promise<Remult>;
|
package/server/expressBridge.js
CHANGED
|
@@ -4,7 +4,6 @@ exports.JobsInQueueEntity = exports.EntityQueueStorage = exports.ExpressRequestB
|
|
|
4
4
|
var tslib_1 = require("tslib");
|
|
5
5
|
var __1 = require("../");
|
|
6
6
|
var express = require("express");
|
|
7
|
-
var bodyParser = require("body-parser");
|
|
8
7
|
var register_actions_on_server_1 = require("./register-actions-on-server");
|
|
9
8
|
var register_entities_on_server_1 = require("./register-entities-on-server");
|
|
10
9
|
var JsonEntityFileStorage_1 = require("./JsonEntityFileStorage");
|
|
@@ -29,8 +28,10 @@ function remultExpress(options) {
|
|
|
29
28
|
if (!options.queueStorage) {
|
|
30
29
|
options.queueStorage = new InMemoryQueueStorage();
|
|
31
30
|
}
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
if ((options === null || options === void 0 ? void 0 : options.bodyParser) !== false) {
|
|
32
|
+
app.use(express.json({ limit: options.bodySizeLimit }));
|
|
33
|
+
app.use(express.urlencoded({ extended: true, limit: options.bodySizeLimit }));
|
|
34
|
+
}
|
|
34
35
|
var dataProvider;
|
|
35
36
|
if (typeof options.dataProvider === "function") {
|
|
36
37
|
dataProvider = options.dataProvider();
|
|
@@ -62,7 +63,12 @@ function remultExpress(options) {
|
|
|
62
63
|
bridge.logApiEndPoints = options.logApiEndPoints;
|
|
63
64
|
var apiArea = bridge.addArea(__1.Remult.apiBaseUrl);
|
|
64
65
|
if (!options.disableAutoApi) {
|
|
65
|
-
|
|
66
|
+
var actions = [];
|
|
67
|
+
if (options.entities)
|
|
68
|
+
actions.push.apply(actions, tslib_1.__spread(options.entities));
|
|
69
|
+
if (options.controllers)
|
|
70
|
+
actions.push.apply(actions, tslib_1.__spread(options.controllers));
|
|
71
|
+
register_actions_on_server_1.registerActionsOnServer(apiArea, actions);
|
|
66
72
|
register_entities_on_server_1.registerEntitiesOnServer(apiArea);
|
|
67
73
|
}
|
|
68
74
|
return Object.assign(app, {
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.registerActionsOnServer = void 0;
|
|
4
|
+
var tslib_1 = require("tslib");
|
|
4
5
|
var server_action_1 = require("../src/server-action");
|
|
5
|
-
function registerActionsOnServer(area) {
|
|
6
|
+
function registerActionsOnServer(area, controllers) {
|
|
7
|
+
var e_1, _a, e_2, _b;
|
|
6
8
|
var addAction = function (a) {
|
|
7
9
|
var x = a[server_action_1.serverActionField];
|
|
8
10
|
if (!x) {
|
|
@@ -11,8 +13,38 @@ function registerActionsOnServer(area) {
|
|
|
11
13
|
area.addAction(x);
|
|
12
14
|
};
|
|
13
15
|
server_action_1.actionInfo.runningOnServer = true;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
if (controllers && controllers.length > 0) {
|
|
17
|
+
try {
|
|
18
|
+
for (var controllers_1 = tslib_1.__values(controllers), controllers_1_1 = controllers_1.next(); !controllers_1_1.done; controllers_1_1 = controllers_1.next()) {
|
|
19
|
+
var c = controllers_1_1.value;
|
|
20
|
+
var z = c[server_action_1.classBackendMethodsArray];
|
|
21
|
+
if (z)
|
|
22
|
+
try {
|
|
23
|
+
for (var z_1 = (e_2 = void 0, tslib_1.__values(z)), z_1_1 = z_1.next(); !z_1_1.done; z_1_1 = z_1.next()) {
|
|
24
|
+
var a = z_1_1.value;
|
|
25
|
+
addAction(a);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
29
|
+
finally {
|
|
30
|
+
try {
|
|
31
|
+
if (z_1_1 && !z_1_1.done && (_b = z_1.return)) _b.call(z_1);
|
|
32
|
+
}
|
|
33
|
+
finally { if (e_2) throw e_2.error; }
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
38
|
+
finally {
|
|
39
|
+
try {
|
|
40
|
+
if (controllers_1_1 && !controllers_1_1.done && (_a = controllers_1.return)) _a.call(controllers_1);
|
|
41
|
+
}
|
|
42
|
+
finally { if (e_1) throw e_1.error; }
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else
|
|
46
|
+
server_action_1.actionInfo.allActions.forEach(function (a) {
|
|
47
|
+
addAction(a);
|
|
48
|
+
});
|
|
17
49
|
}
|
|
18
50
|
exports.registerActionsOnServer = registerActionsOnServer;
|
|
@@ -4,9 +4,11 @@ exports.registerEntitiesOnServer = void 0;
|
|
|
4
4
|
var remult3_1 = require("../src/remult3");
|
|
5
5
|
var context_1 = require("../src/context");
|
|
6
6
|
var data_api_1 = require("../src/data-api");
|
|
7
|
-
function registerEntitiesOnServer(area) {
|
|
7
|
+
function registerEntitiesOnServer(area, entities) {
|
|
8
|
+
if (!entities)
|
|
9
|
+
entities = context_1.allEntities;
|
|
8
10
|
//add Api Entries
|
|
9
|
-
|
|
11
|
+
entities.forEach(function (e) {
|
|
10
12
|
var key = remult3_1.getEntityKey(e);
|
|
11
13
|
if (key != undefined)
|
|
12
14
|
area.add(key, function (c) {
|
|
@@ -6,7 +6,7 @@ export declare class WebSqlDataProvider implements SqlImplementation, __RowsOfDa
|
|
|
6
6
|
rows: {
|
|
7
7
|
[tableName: string]: any;
|
|
8
8
|
};
|
|
9
|
-
constructor(databaseName: string);
|
|
9
|
+
constructor(databaseName: string, databaseSize?: number);
|
|
10
10
|
getLimitSqlSyntax(limit: number, offset: number): string;
|
|
11
11
|
entityIsUsedForTheFirstTime(entity: EntityMetadata): Promise<void>;
|
|
12
12
|
dropTable(entity: EntityMetadata): Promise<void>;
|
|
@@ -7,10 +7,11 @@ var sql_database_1 = require("./sql-database");
|
|
|
7
7
|
var filter_consumer_bridge_to_sql_request_1 = require("../filter/filter-consumer-bridge-to-sql-request");
|
|
8
8
|
//SqlDatabase.LogToConsole = true;
|
|
9
9
|
var WebSqlDataProvider = /** @class */ (function () {
|
|
10
|
-
function WebSqlDataProvider(databaseName) {
|
|
10
|
+
function WebSqlDataProvider(databaseName, databaseSize) {
|
|
11
|
+
if (databaseSize === void 0) { databaseSize = 2 * 1024 * 1024; }
|
|
11
12
|
this.databaseName = databaseName;
|
|
12
13
|
//@ts-ignore
|
|
13
|
-
this.db = window.openDatabase(databaseName, '1.0', databaseName,
|
|
14
|
+
this.db = window.openDatabase(databaseName, '1.0', databaseName, databaseSize);
|
|
14
15
|
}
|
|
15
16
|
WebSqlDataProvider.prototype.getLimitSqlSyntax = function (limit, offset) {
|
|
16
17
|
return ' limit ' + limit + ' offset ' + offset;
|
|
@@ -26,17 +26,17 @@ export declare class RepositoryImplementation<entityType> implements Repository<
|
|
|
26
26
|
query(options?: QueryOptions<entityType>): QueryResult<entityType>;
|
|
27
27
|
getEntityRef(entity: entityType): EntityRef<entityType>;
|
|
28
28
|
delete(id: (entityType extends {
|
|
29
|
-
id
|
|
29
|
+
id?: number;
|
|
30
30
|
} ? number : entityType extends {
|
|
31
|
-
id
|
|
31
|
+
id?: string;
|
|
32
32
|
} ? string : (string | number))): Promise<void>;
|
|
33
33
|
delete(item: entityType): Promise<void>;
|
|
34
34
|
insert(item: Partial<OmitEB<entityType>>[]): Promise<entityType[]>;
|
|
35
35
|
insert(item: Partial<OmitEB<entityType>>): Promise<entityType>;
|
|
36
36
|
update(id: (entityType extends {
|
|
37
|
-
id
|
|
37
|
+
id?: number;
|
|
38
38
|
} ? number : entityType extends {
|
|
39
|
-
id
|
|
39
|
+
id?: string;
|
|
40
40
|
} ? string : (string | number)), entity: Partial<OmitEB<entityType>>): Promise<entityType>;
|
|
41
41
|
private getRefForExistingRow;
|
|
42
42
|
save(item: Partial<OmitEB<entityType>>[]): Promise<entityType[]>;
|
|
@@ -157,6 +157,7 @@ export declare class FieldRefImplementation<entityType, valueType> implements Fi
|
|
|
157
157
|
get originalValue(): any;
|
|
158
158
|
private rawOriginalValue;
|
|
159
159
|
setId(id: (string | number)): void;
|
|
160
|
+
getId(): any;
|
|
160
161
|
get inputValue(): string;
|
|
161
162
|
set inputValue(val: string);
|
|
162
163
|
valueChanged(): boolean;
|
|
@@ -223,7 +224,7 @@ export declare function isAutoIncrement(f: FieldMetadata): boolean;
|
|
|
223
224
|
export interface StringFieldOptions<entityType = any> extends FieldOptions<entityType, string> {
|
|
224
225
|
maxLength?: number;
|
|
225
226
|
}
|
|
226
|
-
export declare function ValueListFieldType<
|
|
227
|
+
export declare function ValueListFieldType<valueType extends ValueListItem = any>(...options: (ValueListFieldOptions<any, valueType> | ((options: FieldOptions<any, valueType>, remult: Remult) => void))[]): (type: ClassType<valueType>) => void;
|
|
227
228
|
export interface ValueListFieldOptions<entityType, valueType> extends FieldOptions<entityType, valueType> {
|
|
228
229
|
getValues?: () => valueType[];
|
|
229
230
|
}
|
|
@@ -200,49 +200,50 @@ var RepositoryImplementation = /** @class */ (function () {
|
|
|
200
200
|
};
|
|
201
201
|
RepositoryImplementation.prototype.insert = function (entity) {
|
|
202
202
|
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
203
|
-
var entity_1, entity_1_1, item, e_4_1, ref;
|
|
204
|
-
var e_4,
|
|
205
|
-
return tslib_1.__generator(this, function (
|
|
206
|
-
switch (
|
|
203
|
+
var r, entity_1, entity_1_1, item, _a, _b, e_4_1, ref;
|
|
204
|
+
var e_4, _c;
|
|
205
|
+
return tslib_1.__generator(this, function (_d) {
|
|
206
|
+
switch (_d.label) {
|
|
207
207
|
case 0:
|
|
208
208
|
if (!Array.isArray(entity)) return [3 /*break*/, 9];
|
|
209
|
-
|
|
209
|
+
r = [];
|
|
210
|
+
_d.label = 1;
|
|
210
211
|
case 1:
|
|
211
|
-
|
|
212
|
+
_d.trys.push([1, 6, 7, 8]);
|
|
212
213
|
entity_1 = tslib_1.__values(entity), entity_1_1 = entity_1.next();
|
|
213
|
-
|
|
214
|
+
_d.label = 2;
|
|
214
215
|
case 2:
|
|
215
216
|
if (!!entity_1_1.done) return [3 /*break*/, 5];
|
|
216
217
|
item = entity_1_1.value;
|
|
218
|
+
_b = (_a = r).push;
|
|
217
219
|
return [4 /*yield*/, this.insert(item)];
|
|
218
220
|
case 3:
|
|
219
|
-
_b.sent();
|
|
220
|
-
|
|
221
|
+
_b.apply(_a, [_d.sent()]);
|
|
222
|
+
_d.label = 4;
|
|
221
223
|
case 4:
|
|
222
224
|
entity_1_1 = entity_1.next();
|
|
223
225
|
return [3 /*break*/, 2];
|
|
224
226
|
case 5: return [3 /*break*/, 8];
|
|
225
227
|
case 6:
|
|
226
|
-
e_4_1 =
|
|
228
|
+
e_4_1 = _d.sent();
|
|
227
229
|
e_4 = { error: e_4_1 };
|
|
228
230
|
return [3 /*break*/, 8];
|
|
229
231
|
case 7:
|
|
230
232
|
try {
|
|
231
|
-
if (entity_1_1 && !entity_1_1.done && (
|
|
233
|
+
if (entity_1_1 && !entity_1_1.done && (_c = entity_1.return)) _c.call(entity_1);
|
|
232
234
|
}
|
|
233
235
|
finally { if (e_4) throw e_4.error; }
|
|
234
236
|
return [7 /*endfinally*/];
|
|
235
|
-
case 8: return [
|
|
237
|
+
case 8: return [2 /*return*/, r];
|
|
236
238
|
case 9:
|
|
237
239
|
ref = getEntityRef(entity, false);
|
|
238
240
|
if (!ref) return [3 /*break*/, 11];
|
|
239
241
|
if (!ref.isNew())
|
|
240
242
|
throw "Item is not new";
|
|
241
243
|
return [4 /*yield*/, ref.save()];
|
|
242
|
-
case 10: return [2 /*return*/,
|
|
244
|
+
case 10: return [2 /*return*/, _d.sent()];
|
|
243
245
|
case 11: return [4 /*yield*/, this.getEntityRef(this.create(entity)).save()];
|
|
244
|
-
case 12: return [2 /*return*/,
|
|
245
|
-
case 13: return [2 /*return*/];
|
|
246
|
+
case 12: return [2 /*return*/, _d.sent()];
|
|
246
247
|
}
|
|
247
248
|
});
|
|
248
249
|
});
|
|
@@ -298,7 +299,7 @@ var RepositoryImplementation = /** @class */ (function () {
|
|
|
298
299
|
switch (_a.label) {
|
|
299
300
|
case 0:
|
|
300
301
|
if (!Array.isArray(entity)) return [3 /*break*/, 1];
|
|
301
|
-
return [2 /*return*/, Promise.all(entity.map(function (x) { return _this.
|
|
302
|
+
return [2 /*return*/, Promise.all(entity.map(function (x) { return _this.save(x); }))];
|
|
302
303
|
case 1:
|
|
303
304
|
ref = getEntityRef(entity, false);
|
|
304
305
|
if (!ref) return [3 /*break*/, 3];
|
|
@@ -649,23 +650,24 @@ var RepositoryImplementation = /** @class */ (function () {
|
|
|
649
650
|
exports.RepositoryImplementation = RepositoryImplementation;
|
|
650
651
|
function __updateEntityBasedOnWhere(entityDefs, where, r) {
|
|
651
652
|
var w = filter_interfaces_1.Filter.fromEntityFilter(entityDefs, where);
|
|
653
|
+
var emptyFunction = function () { };
|
|
652
654
|
if (w) {
|
|
653
655
|
w.__applyToConsumer({
|
|
654
|
-
custom:
|
|
655
|
-
databaseCustom:
|
|
656
|
-
containsCaseInsensitive:
|
|
657
|
-
isDifferentFrom:
|
|
656
|
+
custom: emptyFunction,
|
|
657
|
+
databaseCustom: emptyFunction,
|
|
658
|
+
containsCaseInsensitive: emptyFunction,
|
|
659
|
+
isDifferentFrom: emptyFunction,
|
|
658
660
|
isEqualTo: function (col, val) {
|
|
659
661
|
r[col.key] = val;
|
|
660
662
|
},
|
|
661
|
-
isGreaterOrEqualTo:
|
|
662
|
-
isGreaterThan:
|
|
663
|
-
isIn:
|
|
664
|
-
isLessOrEqualTo:
|
|
665
|
-
isLessThan:
|
|
666
|
-
isNotNull:
|
|
667
|
-
isNull:
|
|
668
|
-
or:
|
|
663
|
+
isGreaterOrEqualTo: emptyFunction,
|
|
664
|
+
isGreaterThan: emptyFunction,
|
|
665
|
+
isIn: emptyFunction,
|
|
666
|
+
isLessOrEqualTo: emptyFunction,
|
|
667
|
+
isLessThan: emptyFunction,
|
|
668
|
+
isNotNull: emptyFunction,
|
|
669
|
+
isNull: emptyFunction,
|
|
670
|
+
or: emptyFunction
|
|
669
671
|
});
|
|
670
672
|
}
|
|
671
673
|
}
|
|
@@ -1895,6 +1897,12 @@ var FieldRefImplementation = /** @class */ (function () {
|
|
|
1895
1897
|
FieldRefImplementation.prototype.setId = function (id) {
|
|
1896
1898
|
this.value = id;
|
|
1897
1899
|
};
|
|
1900
|
+
FieldRefImplementation.prototype.getId = function () {
|
|
1901
|
+
var lu = this.rowBase.lookups.get(this.metadata.key);
|
|
1902
|
+
if (lu)
|
|
1903
|
+
return lu.id != undefined ? lu.id : null;
|
|
1904
|
+
return this.value;
|
|
1905
|
+
};
|
|
1898
1906
|
Object.defineProperty(FieldRefImplementation.prototype, "inputValue", {
|
|
1899
1907
|
get: function () {
|
|
1900
1908
|
this.reportObserved();
|
package/src/remult3/remult3.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ export interface Subscribable {
|
|
|
42
42
|
}
|
|
43
43
|
export declare type FieldsRef<entityType> = {
|
|
44
44
|
[Properties in keyof OmitEB<entityType>]: entityType[Properties] extends {
|
|
45
|
-
id
|
|
45
|
+
id?: (number | string);
|
|
46
46
|
} ? IdFieldRef<entityType, entityType[Properties]> : FieldRef<entityType, entityType[Properties]>;
|
|
47
47
|
} & {
|
|
48
48
|
find(fieldMetadataOrKey: FieldMetadata | string): FieldRef<entityType, any>;
|
|
@@ -63,10 +63,15 @@ export declare type SortSegments<entityType> = {
|
|
|
63
63
|
};
|
|
64
64
|
export interface IdFieldRef<entityType, valueType> extends FieldRef<entityType, valueType> {
|
|
65
65
|
setId(id: valueType extends {
|
|
66
|
-
id
|
|
66
|
+
id?: number;
|
|
67
67
|
} ? number : valueType extends {
|
|
68
|
-
id
|
|
68
|
+
id?: string;
|
|
69
69
|
} ? string : (string | number)): any;
|
|
70
|
+
getId(): (valueType extends {
|
|
71
|
+
id?: number;
|
|
72
|
+
} ? number : valueType extends {
|
|
73
|
+
id?: string;
|
|
74
|
+
} ? string : (string | number));
|
|
70
75
|
}
|
|
71
76
|
export interface FieldRef<entityType = any, valueType = any> extends Subscribable {
|
|
72
77
|
error: string;
|
|
@@ -77,7 +82,7 @@ export interface FieldRef<entityType = any, valueType = any> extends Subscribabl
|
|
|
77
82
|
valueChanged(): boolean;
|
|
78
83
|
entityRef: EntityRef<entityType>;
|
|
79
84
|
container: entityType;
|
|
80
|
-
metadata: FieldMetadata<
|
|
85
|
+
metadata: FieldMetadata<valueType>;
|
|
81
86
|
load(): Promise<valueType>;
|
|
82
87
|
valueIsNull(): boolean;
|
|
83
88
|
originalValueIsNull(): boolean;
|
|
@@ -111,9 +116,9 @@ export interface Repository<entityType> {
|
|
|
111
116
|
findFirst(where?: EntityFilter<entityType>, options?: FindFirstOptions<entityType>): Promise<entityType>;
|
|
112
117
|
/** returns the items that matches the idm the result is cached unless specified differently in the `options` parameter */
|
|
113
118
|
findId(id: entityType extends {
|
|
114
|
-
id
|
|
119
|
+
id?: number;
|
|
115
120
|
} ? number : entityType extends {
|
|
116
|
-
id
|
|
121
|
+
id?: string;
|
|
117
122
|
} ? string : (string | number), options?: FindFirstOptionsBase<entityType>): Promise<entityType>;
|
|
118
123
|
/** An alternative form of fetching data from the API server, which is intended for operating on large numbers of entity objects.
|
|
119
124
|
*
|
|
@@ -152,15 +157,15 @@ export interface Repository<entityType> {
|
|
|
152
157
|
* taskRepo.update(task.id,{...task,completed:true})
|
|
153
158
|
*/
|
|
154
159
|
update(id: (entityType extends {
|
|
155
|
-
id
|
|
160
|
+
id?: number;
|
|
156
161
|
} ? number : entityType extends {
|
|
157
|
-
id
|
|
162
|
+
id?: string;
|
|
158
163
|
} ? string : (string | number)), item: Partial<OmitEB<entityType>>): Promise<entityType>;
|
|
159
164
|
/** Deletes an Item*/
|
|
160
165
|
delete(id: (entityType extends {
|
|
161
|
-
id
|
|
166
|
+
id?: number;
|
|
162
167
|
} ? number : entityType extends {
|
|
163
|
-
id
|
|
168
|
+
id?: string;
|
|
164
169
|
} ? string : (string | number))): Promise<void>;
|
|
165
170
|
delete(item: entityType): Promise<void>;
|
|
166
171
|
/** Creates an instance of an item. It'll not be saved to the data source unless `save` or `insert` will be called for that item */
|
|
@@ -205,7 +210,7 @@ export declare type EntityOrderBy<entityType> = {
|
|
|
205
210
|
*/
|
|
206
211
|
export declare type EntityFilter<entityType> = {
|
|
207
212
|
[Properties in keyof Partial<OmitEB<entityType>>]?: (Partial<OmitEB<entityType>>[Properties] extends (number | Date | undefined) ? ComparisonValueFilter<Partial<OmitEB<entityType>>[Properties]> : Partial<OmitEB<entityType>>[Properties] extends (string | undefined) ? ContainsStringValueFilter & ComparisonValueFilter<string> : Partial<OmitEB<entityType>>[Properties] extends (boolean | undefined) ? ValueFilter<boolean> : Partial<OmitEB<entityType>>[Properties] extends ({
|
|
208
|
-
id
|
|
213
|
+
id?: (string | number);
|
|
209
214
|
} | undefined) ? IdFilter<Partial<OmitEB<entityType>>[Properties]> : ValueFilter<Partial<OmitEB<entityType>>[Properties]>) & ContainsStringValueFilter;
|
|
210
215
|
} & {
|
|
211
216
|
$or?: EntityFilter<entityType>[];
|
|
@@ -230,7 +235,7 @@ export interface ContainsStringValueFilter {
|
|
|
230
235
|
}
|
|
231
236
|
export declare type IdFilter<valueType> = ValueFilter<valueType> | {
|
|
232
237
|
$id: ValueFilter<valueType extends {
|
|
233
|
-
id
|
|
238
|
+
id?: number;
|
|
234
239
|
} ? number : string>;
|
|
235
240
|
};
|
|
236
241
|
export interface LoadOptions<entityType> {
|
|
@@ -240,7 +245,7 @@ export interface FindOptionsBase<entityType> extends LoadOptions<entityType> {
|
|
|
240
245
|
/** filters the data
|
|
241
246
|
* @example
|
|
242
247
|
* await taskRepo.find({where: { completed:false }})
|
|
243
|
-
* @see For more usage examples see [EntityFilter](https://remult.
|
|
248
|
+
* @see For more usage examples see [EntityFilter](https://remult.dev/docs/entityFilter.html)
|
|
244
249
|
*/
|
|
245
250
|
where?: EntityFilter<entityType>;
|
|
246
251
|
/** Determines the order of items returned .
|
package/src/server-action.d.ts
CHANGED
|
@@ -66,4 +66,5 @@ export declare class ProgressListener {
|
|
|
66
66
|
}
|
|
67
67
|
export declare function prepareArgsToSend(types: any[], args: any[]): any[];
|
|
68
68
|
export declare function prepareReceivedArgs(types: any[], args: any[], remult: Remult, ds: DataProvider, res: DataApiResponse): Promise<any[]>;
|
|
69
|
+
export declare const classBackendMethodsArray: unique symbol;
|
|
69
70
|
export {};
|
package/src/server-action.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.prepareReceivedArgs = exports.prepareArgsToSend = exports.ProgressListener = exports.BackendMethod = exports.Controller = exports.serverActionField = exports.actionInfo = exports.myServerAction = exports.Action = void 0;
|
|
3
|
+
exports.classBackendMethodsArray = exports.prepareReceivedArgs = exports.prepareArgsToSend = exports.ProgressListener = exports.BackendMethod = exports.Controller = exports.serverActionField = exports.actionInfo = exports.myServerAction = exports.Action = void 0;
|
|
4
4
|
var tslib_1 = require("tslib");
|
|
5
5
|
require("reflect-metadata");
|
|
6
6
|
var context_1 = require("./context");
|
|
@@ -216,7 +216,7 @@ function BackendMethod(options) {
|
|
|
216
216
|
});
|
|
217
217
|
});
|
|
218
218
|
};
|
|
219
|
-
|
|
219
|
+
registerAction(target, descriptor);
|
|
220
220
|
descriptor.value[exports.serverActionField] = serverAction_1;
|
|
221
221
|
return descriptor;
|
|
222
222
|
}
|
|
@@ -479,7 +479,7 @@ function BackendMethod(options) {
|
|
|
479
479
|
});
|
|
480
480
|
});
|
|
481
481
|
};
|
|
482
|
-
|
|
482
|
+
registerAction(target.constructor, descriptor);
|
|
483
483
|
descriptor.value[exports.serverActionField] = serverAction;
|
|
484
484
|
return descriptor;
|
|
485
485
|
};
|
|
@@ -488,6 +488,10 @@ exports.BackendMethod = BackendMethod;
|
|
|
488
488
|
var customUndefined = {
|
|
489
489
|
_isUndefined: true
|
|
490
490
|
};
|
|
491
|
+
function registerAction(target, descriptor) {
|
|
492
|
+
(target[exports.classBackendMethodsArray] || (target[exports.classBackendMethodsArray] = [])).push(descriptor.value);
|
|
493
|
+
exports.actionInfo.allActions.push(descriptor.value);
|
|
494
|
+
}
|
|
491
495
|
function isCustomUndefined(x) {
|
|
492
496
|
return x && x._isUndefined;
|
|
493
497
|
}
|
|
@@ -592,3 +596,4 @@ function prepareReceivedArgs(types, args, remult, ds, res) {
|
|
|
592
596
|
});
|
|
593
597
|
}
|
|
594
598
|
exports.prepareReceivedArgs = prepareReceivedArgs;
|
|
599
|
+
exports.classBackendMethodsArray = Symbol('classBackendMethodsArray');
|
|
@@ -64,26 +64,12 @@ var entityWithValidations = /** @class */ (function (_super) {
|
|
|
64
64
|
remult3_1.Entity('', {
|
|
65
65
|
allowApiCrud: true,
|
|
66
66
|
saving: function (t) { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
|
|
67
|
-
var e;
|
|
68
67
|
return tslib_1.__generator(this, function (_a) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return [4 /*yield*/, t.remult.repo(entityWithValidations_1).find({
|
|
75
|
-
orderBy: { myId: "desc" },
|
|
76
|
-
limit: 1
|
|
77
|
-
})];
|
|
78
|
-
case 1:
|
|
79
|
-
e = _a.sent();
|
|
80
|
-
t.myId = e.length ? e[0].myId + 1 : 1;
|
|
81
|
-
_a.label = 2;
|
|
82
|
-
case 2:
|
|
83
|
-
if (!exports.testConfiguration.restDbRunningOnServer)
|
|
84
|
-
entityWithValidations_1.savingRowCount++;
|
|
85
|
-
return [2 /*return*/];
|
|
86
|
-
}
|
|
68
|
+
if (!t.name || t.name.length < 3)
|
|
69
|
+
t._.fields.name.error = 'invalid';
|
|
70
|
+
if (!exports.testConfiguration.restDbRunningOnServer)
|
|
71
|
+
entityWithValidations_1.savingRowCount++;
|
|
72
|
+
return [2 /*return*/];
|
|
87
73
|
});
|
|
88
74
|
}); }
|
|
89
75
|
}),
|
|
@@ -7,22 +7,22 @@ var TestDataApiResponse = /** @class */ (function () {
|
|
|
7
7
|
TestDataApiResponse.prototype.progress = function (progress) {
|
|
8
8
|
};
|
|
9
9
|
TestDataApiResponse.prototype.success = function (data) {
|
|
10
|
-
|
|
10
|
+
throw new Error(('didnt expect success: ' + JSON.stringify(data)));
|
|
11
11
|
};
|
|
12
12
|
TestDataApiResponse.prototype.forbidden = function () {
|
|
13
|
-
|
|
13
|
+
throw new Error('didnt expect forbidden:');
|
|
14
14
|
};
|
|
15
15
|
TestDataApiResponse.prototype.created = function (data) {
|
|
16
|
-
|
|
16
|
+
throw new Error('didnt expect created: ' + JSON.stringify(data));
|
|
17
17
|
};
|
|
18
18
|
TestDataApiResponse.prototype.deleted = function () {
|
|
19
|
-
|
|
19
|
+
throw new Error('didnt expect deleted:');
|
|
20
20
|
};
|
|
21
21
|
TestDataApiResponse.prototype.notFound = function () {
|
|
22
|
-
|
|
22
|
+
throw new Error('not found');
|
|
23
23
|
};
|
|
24
24
|
TestDataApiResponse.prototype.error = function (data) {
|
|
25
|
-
|
|
25
|
+
throw new Error('error: ' + data + " " + JSON.stringify(data));
|
|
26
26
|
};
|
|
27
27
|
return TestDataApiResponse;
|
|
28
28
|
}());
|
package/src/tests/d.d.ts
CHANGED
package/src/tests/d.js
CHANGED
|
@@ -2,22 +2,12 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.d = void 0;
|
|
4
4
|
var tslib_1 = require("tslib");
|
|
5
|
-
var server_action_1 = require("../server-action");
|
|
6
5
|
var remult3_1 = require("../remult3");
|
|
7
|
-
var dWithPrefilter_1 = require("./dWithPrefilter");
|
|
8
6
|
var d = /** @class */ (function (_super) {
|
|
9
7
|
tslib_1.__extends(d, _super);
|
|
10
8
|
function d() {
|
|
11
9
|
return _super !== null && _super.apply(this, arguments) || this;
|
|
12
10
|
}
|
|
13
|
-
d.prototype.doIt = function () {
|
|
14
|
-
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
15
|
-
return tslib_1.__generator(this, function (_a) {
|
|
16
|
-
dWithPrefilter_1.dWithPrefilter.count++;
|
|
17
|
-
return [2 /*return*/, true];
|
|
18
|
-
});
|
|
19
|
-
});
|
|
20
|
-
};
|
|
21
11
|
d.count = 0;
|
|
22
12
|
tslib_1.__decorate([
|
|
23
13
|
remult3_1.Fields.integer(),
|
|
@@ -27,12 +17,6 @@ var d = /** @class */ (function (_super) {
|
|
|
27
17
|
remult3_1.Fields.integer(),
|
|
28
18
|
tslib_1.__metadata("design:type", Number)
|
|
29
19
|
], d.prototype, "b", void 0);
|
|
30
|
-
tslib_1.__decorate([
|
|
31
|
-
server_action_1.BackendMethod({ allowed: true }),
|
|
32
|
-
tslib_1.__metadata("design:type", Function),
|
|
33
|
-
tslib_1.__metadata("design:paramtypes", []),
|
|
34
|
-
tslib_1.__metadata("design:returntype", Promise)
|
|
35
|
-
], d.prototype, "doIt", null);
|
|
36
20
|
d = tslib_1.__decorate([
|
|
37
21
|
remult3_1.Entity('d1', {
|
|
38
22
|
allowApiCrud: true
|
|
@@ -9,9 +9,6 @@ var Status = /** @class */ (function () {
|
|
|
9
9
|
this.name = name;
|
|
10
10
|
}
|
|
11
11
|
Status_1 = Status;
|
|
12
|
-
Status.prototype.toString = function () {
|
|
13
|
-
return this.name;
|
|
14
|
-
};
|
|
15
12
|
var Status_1;
|
|
16
13
|
Status.open = new Status_1(0, "open");
|
|
17
14
|
Status.closed = new Status_1(1, "closed");
|