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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "remult",
3
- "version": "0.13.20",
4
- "description": "remult core lib",
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=svg">
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://snyk.io/test/npm/remult">
22
- <img alt="snyk" src="https://snyk.io/test/npm/remult/badge.svg"/>
23
- </a>
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 fullstack CRUD framework that uses your TypeScript model types to provide:
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: Monorepos
34
+ #### Remult :heart: Code Sharing
37
35
 
38
- 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 levels.
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. There's one [using a React frontend](https://remult.dev/tutorials/tutorial-react.html) and one [using Angular](https://remult.dev/tutorials/tutorial-angular.html).
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
- ## Define model classes
66
+ ### Define model classes
64
67
  ```ts
65
- import { Entity, EntityBase, Fields } from 'remult';
68
+ import { Entity, Fields } from 'remult';
66
69
 
67
70
  @Entity('products', {
68
71
  allowApiCrud: true
69
72
  })
70
- export class Product extends EntityBase {
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
- ## Find and manipulate data in type-safe frontend code
89
+ ### Find and manipulate data in type-safe frontend code
87
90
  ```ts
88
91
  async function increasePriceOfTofu(priceIncrease: number) {
89
- const product = await remult.repo(Product).findFirst({ name: 'Tofu' });
92
+ const productsRepo = remult.repo(Product);
90
93
 
94
+ const product = await productsRepo.findFirst({ name: 'Tofu' });
91
95
  product.unitPrice += priceIncrease;
92
- product.save();
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 product = await remult!.repo(Product).findFirst({ name: 'Tofu' });
104
+ const productsRepo = remult!.repo(Product);
101
105
 
106
+ const product = await productsRepo.findFirst({ name: 'Tofu' });
102
107
  product.unitPrice += priceIncrease;
103
- product.save();
108
+ productsRepo.save(product);
104
109
  }
105
110
  ```
106
111
 
107
- ## :ballot_box_with_check: Data validation and constraints - defined once
112
+ ### :ballot_box_with_check: Data validation and constraints - defined once
108
113
 
109
114
  ```ts
110
- import { Entity, EntityBase, Fields } from 'remult';
115
+ import { Entity, Fields } from 'remult';
111
116
 
112
117
  @Entity('products', {
113
118
  allowApiCrud: true
114
119
  })
115
- export class Product extends EntityBase {
120
+ export class Product {
116
121
  @Fields.string<Product>({
117
122
  validate: product => {
118
123
  if (product.name.trim().length == 0)
119
- product.$.name.error = 'required';
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
- field.error = "must not be less than 0";
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 = remult.repo(Product).create();
141
+ const product = productsRepo.create();
137
142
 
138
143
  try {
139
- await product.save();
144
+ await productsRepo.save(product);
140
145
  }
141
- catch {
142
- console.error(product._.error); // Browser console will display - "Name: required"
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 -d "{""unitPrice"":-1}" -H "Content-Type: application/json" -X POST http://localhost:3001/api/products
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
- ## :lock: Secure the API with fine-grained authorization
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 extends EntityBase {
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
- /** Determines the Data Provider
10
-
11
- * @see [Optional Databases](https://remult.dev/docs/databases.html)
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>;
@@ -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
- app.use(bodyParser.json({ limit: options.bodySizeLimit }));
33
- app.use(bodyParser.urlencoded({ extended: true, limit: options.bodySizeLimit }));
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
- register_actions_on_server_1.registerActionsOnServer(apiArea);
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,2 +1,3 @@
1
1
  import { SiteArea } from "./expressBridge";
2
- export declare function registerActionsOnServer(area: SiteArea): void;
2
+ import { ClassType } from "../classType";
3
+ export declare function registerActionsOnServer(area: SiteArea, controllers?: ClassType<any>[]): void;
@@ -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
- server_action_1.actionInfo.allActions.forEach(function (a) {
15
- addAction(a);
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;
@@ -1,2 +1,3 @@
1
1
  import { SiteArea } from "./expressBridge";
2
- export declare function registerEntitiesOnServer(area: SiteArea): void;
2
+ import { ClassType } from "../classType";
3
+ export declare function registerEntitiesOnServer(area: SiteArea, entities?: ClassType<any>[]): void;
@@ -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
- context_1.allEntities.forEach(function (e) {
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, 2 * 1024 * 1024);
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: number;
29
+ id?: number;
30
30
  } ? number : entityType extends {
31
- id: string;
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: number;
37
+ id?: number;
38
38
  } ? number : entityType extends {
39
- id: string;
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<entityType = any, valueType extends ValueListItem = any>(...options: (ValueListFieldOptions<entityType, valueType> | ((options: FieldOptions<entityType, valueType>, remult: Remult) => void))[]): (type: ClassType<valueType>) => void;
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, _a;
205
- return tslib_1.__generator(this, function (_b) {
206
- switch (_b.label) {
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
- _b.label = 1;
209
+ r = [];
210
+ _d.label = 1;
210
211
  case 1:
211
- _b.trys.push([1, 6, 7, 8]);
212
+ _d.trys.push([1, 6, 7, 8]);
212
213
  entity_1 = tslib_1.__values(entity), entity_1_1 = entity_1.next();
213
- _b.label = 2;
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
- _b.label = 4;
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 = _b.sent();
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 && (_a = entity_1.return)) _a.call(entity_1);
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 [3 /*break*/, 13];
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*/, _b.sent()];
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*/, _b.sent()];
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.insert(x); }))];
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: function () { },
655
- databaseCustom: function () { },
656
- containsCaseInsensitive: function () { },
657
- isDifferentFrom: function () { },
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: function () { },
662
- isGreaterThan: function () { },
663
- isIn: function () { },
664
- isLessOrEqualTo: function () { },
665
- isLessThan: function () { },
666
- isNotNull: function () { },
667
- isNull: function () { },
668
- or: function () { }
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();
@@ -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: (number | string);
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: number;
66
+ id?: number;
67
67
  } ? number : valueType extends {
68
- id: string;
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<entityType>;
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: number;
119
+ id?: number;
115
120
  } ? number : entityType extends {
116
- id: string;
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: number;
160
+ id?: number;
156
161
  } ? number : entityType extends {
157
- id: string;
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: number;
166
+ id?: number;
162
167
  } ? number : entityType extends {
163
- id: string;
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: (string | number);
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: number;
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.github.io/guide/entityFilter.html)
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 .
@@ -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 {};
@@ -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
- exports.actionInfo.allActions.push(descriptor.value);
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
- exports.actionInfo.allActions.push(descriptor.value);
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
- switch (_a.label) {
70
- case 0:
71
- if (!t.name || t.name.length < 3)
72
- t._.fields.name.error = 'invalid';
73
- if (!(t._.isNew() && (!t.myId || t.myId == 0))) return [3 /*break*/, 2];
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
- fail('didnt expect success: ' + JSON.stringify(data));
10
+ throw new Error(('didnt expect success: ' + JSON.stringify(data)));
11
11
  };
12
12
  TestDataApiResponse.prototype.forbidden = function () {
13
- fail('didnt expect forbidden:');
13
+ throw new Error('didnt expect forbidden:');
14
14
  };
15
15
  TestDataApiResponse.prototype.created = function (data) {
16
- fail('didnt expect created: ' + JSON.stringify(data));
16
+ throw new Error('didnt expect created: ' + JSON.stringify(data));
17
17
  };
18
18
  TestDataApiResponse.prototype.deleted = function () {
19
- fail('didnt expect deleted:');
19
+ throw new Error('didnt expect deleted:');
20
20
  };
21
21
  TestDataApiResponse.prototype.notFound = function () {
22
- fail('not found');
22
+ throw new Error('not found');
23
23
  };
24
24
  TestDataApiResponse.prototype.error = function (data) {
25
- fail('error: ' + data + " " + JSON.stringify(data));
25
+ throw new Error('error: ' + data + " " + JSON.stringify(data));
26
26
  };
27
27
  return TestDataApiResponse;
28
28
  }());
package/src/tests/d.d.ts CHANGED
@@ -3,5 +3,4 @@ export declare class d extends EntityBase {
3
3
  id: number;
4
4
  b: number;
5
5
  static count: number;
6
- doIt(): Promise<boolean>;
7
6
  }
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
@@ -5,7 +5,6 @@ export declare class Status {
5
5
  static closed: Status;
6
6
  static hold: Status;
7
7
  constructor(id: number, name: string);
8
- toString(): string;
9
8
  }
10
9
  export declare class TestStatus {
11
10
  id?: string;
@@ -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");