remult 0.13.19 → 0.13.22

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/src/context.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.EventSource = exports.queryConfig = exports.Allow = exports.setControllerSettings = exports.MethodHelper = exports.ClassHelper = exports.classHelpers = exports.allEntities = exports.Remult = exports.isBackend = exports.processHttpException = exports.toPromise = void 0;
3
+ exports.EventSource = exports.queryConfig = exports.Allow = exports.setControllerSettings = exports.MethodHelper = exports.ClassHelper = exports.classHelpers = exports.allEntities = exports.Remult = exports.isBackend = exports.processHttpException = exports.toPromise = exports.retry = exports.HttpProviderBridgeToRestDataProviderHttpProvider = void 0;
4
4
  var tslib_1 = require("tslib");
5
5
  var server_action_1 = require("./server-action");
6
6
  var rest_data_provider_1 = require("./data-providers/rest-data-provider");
@@ -39,29 +39,30 @@ var HttpProviderBridgeToRestDataProviderHttpProvider = /** @class */ (function (
39
39
  };
40
40
  return HttpProviderBridgeToRestDataProviderHttpProvider;
41
41
  }());
42
+ exports.HttpProviderBridgeToRestDataProviderHttpProvider = HttpProviderBridgeToRestDataProviderHttpProvider;
42
43
  function retry(what) {
43
- var _a, _b;
44
+ var _a, _b, _c;
44
45
  return tslib_1.__awaiter(this, void 0, void 0, function () {
45
46
  var err_1;
46
- return tslib_1.__generator(this, function (_c) {
47
- switch (_c.label) {
47
+ return tslib_1.__generator(this, function (_d) {
48
+ switch (_d.label) {
48
49
  case 0:
49
50
  if (!true) return [3 /*break*/, 7];
50
- _c.label = 1;
51
+ _d.label = 1;
51
52
  case 1:
52
- _c.trys.push([1, 3, , 6]);
53
+ _d.trys.push([1, 3, , 6]);
53
54
  return [4 /*yield*/, what()];
54
- case 2: return [2 /*return*/, _c.sent()];
55
+ case 2: return [2 /*return*/, _d.sent()];
55
56
  case 3:
56
- err_1 = _c.sent();
57
- if (!(((_a = err_1.message) === null || _a === void 0 ? void 0 : _a.startsWith("Error occurred while trying to proxy")) || ((_b = err_1.message) === null || _b === void 0 ? void 0 : _b.startsWith("Error occured while trying to proxy")))) return [3 /*break*/, 5];
57
+ err_1 = _d.sent();
58
+ if (!(((_a = err_1.message) === null || _a === void 0 ? void 0 : _a.startsWith("Error occurred while trying to proxy")) || ((_b = err_1.message) === null || _b === void 0 ? void 0 : _b.startsWith("Error occured while trying to proxy")) || ((_c = err_1.message) === null || _c === void 0 ? void 0 : _c.startsWith("Gateway Timeout")))) return [3 /*break*/, 5];
58
59
  return [4 /*yield*/, new Promise(function (res, req) {
59
60
  setTimeout(function () {
60
61
  res({});
61
62
  }, 250);
62
63
  })];
63
64
  case 4:
64
- _c.sent();
65
+ _d.sent();
65
66
  return [3 /*break*/, 0];
66
67
  case 5: throw err_1;
67
68
  case 6: return [3 /*break*/, 0];
@@ -70,6 +71,7 @@ function retry(what) {
70
71
  });
71
72
  });
72
73
  }
74
+ exports.retry = retry;
73
75
  function toPromise(p) {
74
76
  var _this = this;
75
77
  var r;
@@ -139,6 +141,12 @@ function isBackend() {
139
141
  }
140
142
  exports.isBackend = isBackend;
141
143
  var Remult = /** @class */ (function () {
144
+ /** Creates a new instance of the `remult` object.
145
+ *
146
+ * Can receive either an HttpProvider or a DataProvider as a parameter - which will be used to fetch data from.
147
+ *
148
+ * If no provider is specified, `fetch` will be used as an http provider
149
+ */
142
150
  function Remult(provider) {
143
151
  this._userChangeEvent = new EventSource();
144
152
  this.repCache = new Map();
@@ -158,16 +166,26 @@ var Remult = /** @class */ (function () {
158
166
  if (!server_action_1.Action.provider)
159
167
  server_action_1.Action.provider = dataProvider;
160
168
  }
161
- Remult.prototype.clearAllCache = function () {
162
- this.repCache.clear();
163
- };
164
- Remult.prototype.authenticated = function () {
165
- return this.user.id !== undefined;
166
- };
167
- Remult.prototype.setDataProvider = function (dataProvider) {
168
- this._dataSource = dataProvider;
169
+ /**Return's a `Repository` of the specific entity type
170
+ * @example
171
+ * const taskRepo = remult.repo(Task);
172
+ * @see [Repository](https://remult.dev/docs/ref_repository.html)
173
+ *
174
+ */
175
+ Remult.prototype.repo = function (entity, dataProvider) {
176
+ if (dataProvider === undefined)
177
+ dataProvider = this._dataSource;
178
+ var dpCache = this.repCache.get(dataProvider);
179
+ if (!dpCache)
180
+ this.repCache.set(dataProvider, dpCache = new Map());
181
+ var r = dpCache.get(entity);
182
+ if (!r) {
183
+ dpCache.set(entity, r = new RepositoryImplementation_1.RepositoryImplementation(entity, this, dataProvider));
184
+ }
185
+ return r;
169
186
  };
170
187
  Object.defineProperty(Remult.prototype, "user", {
188
+ /** Returns the current user's info */
171
189
  get: function () {
172
190
  if (this._user === undefined) {
173
191
  return {
@@ -181,70 +199,44 @@ var Remult = /** @class */ (function () {
181
199
  enumerable: false,
182
200
  configurable: true
183
201
  });
184
- Object.defineProperty(Remult.prototype, "userChange", {
185
- get: function () {
186
- return this._userChangeEvent.dispatcher;
187
- },
188
- enumerable: false,
189
- configurable: true
190
- });
202
+ /** Set's the current user info */
191
203
  Remult.prototype.setUser = function (info) {
192
- var _a;
193
204
  return tslib_1.__awaiter(this, void 0, void 0, function () {
194
205
  var auth;
195
- return tslib_1.__generator(this, function (_b) {
196
- switch (_b.label) {
206
+ return tslib_1.__generator(this, function (_a) {
207
+ switch (_a.label) {
197
208
  case 0:
198
209
  this._user = info;
199
210
  auth = info;
200
211
  if (auth) {
201
212
  if (!this._user.id && auth.sub)
202
213
  this._user.id = auth.sub;
203
- if (!this._user.name && auth.name)
204
- this._user.name = auth.name;
205
214
  if (!this._user.roles && auth.permissions) {
206
215
  this._user.roles = auth.permissions;
207
216
  }
208
217
  }
209
- if (this._user && !((_a = this._user) === null || _a === void 0 ? void 0 : _a.roles))
218
+ if (this._user && !this._user.roles)
210
219
  this._user.roles = [];
211
220
  return [4 /*yield*/, this._userChangeEvent.fire()];
212
221
  case 1:
213
- _b.sent();
222
+ _a.sent();
214
223
  return [2 /*return*/];
215
224
  }
216
225
  });
217
226
  });
218
227
  };
219
- Remult.prototype.isAllowedForInstance = function (instance, x) {
220
- var e_1, _a;
221
- if (Array.isArray(x)) {
222
- {
223
- try {
224
- for (var x_1 = tslib_1.__values(x), x_1_1 = x_1.next(); !x_1_1.done; x_1_1 = x_1.next()) {
225
- var item = x_1_1.value;
226
- if (this.isAllowedForInstance(instance, item))
227
- return true;
228
- }
229
- }
230
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
231
- finally {
232
- try {
233
- if (x_1_1 && !x_1_1.done && (_a = x_1.return)) _a.call(x_1);
234
- }
235
- finally { if (e_1) throw e_1.error; }
236
- }
237
- }
238
- }
239
- else if (typeof (x) === "function") {
240
- return x(this, instance);
241
- }
242
- else
243
- return this.isAllowed(x);
228
+ /** Checks if a user was authenticated */
229
+ Remult.prototype.authenticated = function () {
230
+ return this.user.id !== undefined;
244
231
  };
232
+ /** checks if the user has any of the roles specified in the parameters
233
+ * @example
234
+ * remult.isAllowed("admin")
235
+ * @see
236
+ * [Allowed](https://remult.dev/docs/allowed.html)
237
+ */
245
238
  Remult.prototype.isAllowed = function (roles) {
246
- var e_2, _a;
247
- var _b, _c;
239
+ var e_1, _a;
248
240
  if (roles == undefined)
249
241
  return undefined;
250
242
  if (roles instanceof Array) {
@@ -256,12 +248,12 @@ var Remult = /** @class */ (function () {
256
248
  }
257
249
  }
258
250
  }
259
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
251
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
260
252
  finally {
261
253
  try {
262
254
  if (roles_1_1 && !roles_1_1.done && (_a = roles_1.return)) _a.call(roles_1);
263
255
  }
264
- finally { if (e_2) throw e_2.error; }
256
+ finally { if (e_1) throw e_1.error; }
265
257
  }
266
258
  return false;
267
259
  }
@@ -270,27 +262,63 @@ var Remult = /** @class */ (function () {
270
262
  }
271
263
  if (typeof roles === 'boolean')
272
264
  return roles;
273
- if (!this.user)
274
- return false;
275
265
  if (typeof roles === 'string')
276
- if (((_c = (_b = this.user) === null || _b === void 0 ? void 0 : _b.roles) === null || _c === void 0 ? void 0 : _c.indexOf(roles.toString())) >= 0)
266
+ if (this.user.roles.indexOf(roles.toString()) >= 0)
277
267
  return true;
278
268
  return false;
279
269
  };
280
- Remult.prototype.repo = function (entity, dataProvider) {
281
- if (dataProvider === undefined)
282
- dataProvider = this._dataSource;
283
- var dpCache = this.repCache.get(dataProvider);
284
- if (!dpCache)
285
- this.repCache.set(dataProvider, dpCache = new Map());
286
- var r = dpCache.get(entity);
287
- if (!r) {
288
- dpCache.set(entity, r = new RepositoryImplementation_1.RepositoryImplementation(entity, this, dataProvider));
270
+ /** checks if the user matches the allowedForInstance callback
271
+ * @see
272
+ * [Allowed](https://remult.dev/docs/allowed.html)
273
+ */
274
+ Remult.prototype.isAllowedForInstance = function (instance, x) {
275
+ var e_2, _a;
276
+ if (Array.isArray(x)) {
277
+ {
278
+ try {
279
+ for (var x_1 = tslib_1.__values(x), x_1_1 = x_1.next(); !x_1_1.done; x_1_1 = x_1.next()) {
280
+ var item = x_1_1.value;
281
+ if (this.isAllowedForInstance(instance, item))
282
+ return true;
283
+ }
284
+ }
285
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
286
+ finally {
287
+ try {
288
+ if (x_1_1 && !x_1_1.done && (_a = x_1.return)) _a.call(x_1);
289
+ }
290
+ finally { if (e_2) throw e_2.error; }
291
+ }
292
+ }
289
293
  }
290
- return r;
294
+ else if (typeof (x) === "function") {
295
+ return x(this, instance);
296
+ }
297
+ else
298
+ return this.isAllowed(x);
291
299
  };
292
- Remult.onFind = function (metadata, options) { };
300
+ Object.defineProperty(Remult.prototype, "userChange", {
301
+ /** returns a dispatcher object that fires once a user has changed*/
302
+ get: function () {
303
+ return this._userChangeEvent.dispatcher;
304
+ },
305
+ enumerable: false,
306
+ configurable: true
307
+ });
308
+ /** sets the current data provider */
309
+ Remult.prototype.setDataProvider = function (dataProvider) {
310
+ this._dataSource = dataProvider;
311
+ };
312
+ Remult.prototype.clearAllCache = function () {
313
+ this.repCache.clear();
314
+ };
315
+ /** The api Base Url to be used in all remult calls. by default it's set to `/api`.
316
+ *
317
+ * Set this property in case you want to determine a non relative api url
318
+ */
293
319
  Remult.apiBaseUrl = '/api';
320
+ /** A helper callback that can be used to debug and trace all find operations. Useful in debugging scenarios */
321
+ Remult.onFind = function (metadata, options) { };
294
322
  return Remult;
295
323
  }());
296
324
  exports.Remult = Remult;
@@ -24,11 +24,12 @@ export declare class RestEntityDataProvider implements EntityDataProvider {
24
24
  insert(data: any): Promise<any>;
25
25
  }
26
26
  export declare class RestDataProviderHttpProviderUsingFetch implements RestDataProviderHttpProvider {
27
- private addRequestHeader?;
28
- constructor(addRequestHeader?: (add: ((name: string, value: string) => void)) => void);
27
+ private fetch?;
28
+ constructor(fetch?: (input: RequestInfo, init?: RequestInit) => Promise<Response>);
29
29
  get(url: string): Promise<any>;
30
30
  put(url: string, data: any): Promise<any>;
31
31
  delete(url: string): Promise<any>;
32
32
  post(url: string, data: any): Promise<any>;
33
+ myFetch(url: string, init?: RequestInit): Promise<any>;
33
34
  }
34
35
  export declare function addFilterToUrlAndReturnTrueIfSuccessful(filter: any, url: UrlBuilder): boolean;
@@ -4,6 +4,7 @@ exports.addFilterToUrlAndReturnTrueIfSuccessful = exports.RestDataProviderHttpPr
4
4
  var tslib_1 = require("tslib");
5
5
  var urlBuilder_1 = require("../../urlBuilder");
6
6
  var filter_interfaces_1 = require("../filter/filter-interfaces");
7
+ var context_1 = require("../context");
7
8
  var RestDataProvider = /** @class */ (function () {
8
9
  function RestDataProvider(url, http) {
9
10
  this.url = url;
@@ -152,67 +153,76 @@ var RestEntityDataProvider = /** @class */ (function () {
152
153
  return RestEntityDataProvider;
153
154
  }());
154
155
  exports.RestEntityDataProvider = RestEntityDataProvider;
155
- function JsonContent(add) {
156
- add('Content-type', "application/json");
157
- }
158
156
  var RestDataProviderHttpProviderUsingFetch = /** @class */ (function () {
159
- function RestDataProviderHttpProviderUsingFetch(addRequestHeader) {
160
- this.addRequestHeader = addRequestHeader;
161
- if (!addRequestHeader)
162
- this.addRequestHeader = function () { };
157
+ function RestDataProviderHttpProviderUsingFetch(fetch) {
158
+ this.fetch = fetch;
163
159
  }
164
160
  RestDataProviderHttpProviderUsingFetch.prototype.get = function (url) {
165
- return myFetch(url, undefined, this.addRequestHeader).then(function (r) {
166
- return r;
161
+ return tslib_1.__awaiter(this, void 0, void 0, function () {
162
+ var _this = this;
163
+ return tslib_1.__generator(this, function (_a) {
164
+ switch (_a.label) {
165
+ case 0: return [4 /*yield*/, context_1.retry(function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
166
+ return tslib_1.__generator(this, function (_a) {
167
+ return [2 /*return*/, this.myFetch(url).then(function (r) {
168
+ return r;
169
+ })];
170
+ });
171
+ }); })];
172
+ case 1: return [2 /*return*/, _a.sent()];
173
+ }
174
+ });
167
175
  });
168
176
  };
169
177
  RestDataProviderHttpProviderUsingFetch.prototype.put = function (url, data) {
170
- return myFetch(url, {
178
+ return this.myFetch(url, {
171
179
  method: 'put',
172
180
  body: JSON.stringify(data)
173
- }, this.addRequestHeader, JsonContent);
181
+ });
174
182
  };
175
183
  RestDataProviderHttpProviderUsingFetch.prototype.delete = function (url) {
176
- var h = new Headers();
177
- this.addRequestHeader(function (name, value) { return h.append(name, value); });
178
- return fetch(url, { method: 'delete', credentials: 'include' }).then(onSuccess, onError);
184
+ return this.myFetch(url, { method: 'delete', credentials: 'include' });
179
185
  };
180
186
  RestDataProviderHttpProviderUsingFetch.prototype.post = function (url, data) {
181
- return myFetch(url, {
182
- method: 'post',
183
- body: JSON.stringify(data)
184
- }, this.addRequestHeader, JsonContent);
187
+ return tslib_1.__awaiter(this, void 0, void 0, function () {
188
+ var _this = this;
189
+ return tslib_1.__generator(this, function (_a) {
190
+ switch (_a.label) {
191
+ case 0: return [4 /*yield*/, context_1.retry(function () { return _this.myFetch(url, {
192
+ method: 'post',
193
+ body: JSON.stringify(data)
194
+ }); })];
195
+ case 1: return [2 /*return*/, _a.sent()];
196
+ }
197
+ });
198
+ });
199
+ };
200
+ RestDataProviderHttpProviderUsingFetch.prototype.myFetch = function (url, init) {
201
+ var _this = this;
202
+ if (!init)
203
+ init = {};
204
+ if (!init.headers)
205
+ init.headers = new Headers();
206
+ var h = init.headers;
207
+ h.append('Content-type', "application/json");
208
+ init.credentials = 'include';
209
+ return (this.fetch || fetch)(url, init).then(function (response) {
210
+ return onSuccess(response);
211
+ }).catch(function (error) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
212
+ var r;
213
+ return tslib_1.__generator(this, function (_a) {
214
+ switch (_a.label) {
215
+ case 0: return [4 /*yield*/, error];
216
+ case 1:
217
+ r = _a.sent();
218
+ throw r;
219
+ }
220
+ });
221
+ }); });
185
222
  };
186
223
  return RestDataProviderHttpProviderUsingFetch;
187
224
  }());
188
225
  exports.RestDataProviderHttpProviderUsingFetch = RestDataProviderHttpProviderUsingFetch;
189
- function myFetch(url, init) {
190
- var _this = this;
191
- var addRequestHeader = [];
192
- for (var _i = 2; _i < arguments.length; _i++) {
193
- addRequestHeader[_i - 2] = arguments[_i];
194
- }
195
- if (!init)
196
- init = {};
197
- if (!init.headers)
198
- init.headers = new Headers();
199
- var h = init.headers;
200
- addRequestHeader.forEach(function (x) { return x(function (n, v) { return h.append(n, v); }); });
201
- init.credentials = 'include';
202
- return fetch(url, init).then(function (response) {
203
- return onSuccess(response);
204
- }).catch(function (error) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
205
- var r;
206
- return tslib_1.__generator(this, function (_a) {
207
- switch (_a.label) {
208
- case 0: return [4 /*yield*/, error];
209
- case 1:
210
- r = _a.sent();
211
- throw r;
212
- }
213
- });
214
- }); });
215
- }
216
226
  function onSuccess(response) {
217
227
  if (response.status == 204)
218
228
  return;
@@ -220,9 +230,7 @@ function onSuccess(response) {
220
230
  return response.json();
221
231
  else {
222
232
  throw response.json().then(function (x) {
223
- if (!x.message)
224
- x.message = response.statusText;
225
- return x;
233
+ return tslib_1.__assign(tslib_1.__assign({}, x), { message: x.message || response.statusText, url: response.url, status: response.status });
226
234
  }).catch(function () {
227
235
  throw {
228
236
  message: response.statusText,
@@ -232,9 +240,6 @@ function onSuccess(response) {
232
240
  });
233
241
  }
234
242
  }
235
- function onError(error) {
236
- throw Promise.resolve(error);
237
- }
238
243
  function addFilterToUrlAndReturnTrueIfSuccessful(filter, url) {
239
244
  for (var key in filter) {
240
245
  if (Object.prototype.hasOwnProperty.call(filter, key)) {
@@ -121,17 +121,13 @@ var LogSQLCommand = /** @class */ (function () {
121
121
  if (this.allQueries) {
122
122
  d = new Date().valueOf() - start.valueOf();
123
123
  if (d > SqlDatabase.durationThreshold) {
124
- console.log('Query:', sql);
125
- console.log("Arguments:", this.args);
126
- console.log("Duration", d / 1000);
124
+ console.log({ query: sql, arguments: this.args, duration: d / 1000 });
127
125
  }
128
126
  }
129
127
  return [2 /*return*/, r];
130
128
  case 2:
131
129
  err_1 = _a.sent();
132
- console.error('Error:', err_1);
133
- console.error('Query:', sql);
134
- console.error("Arguments", this.args);
130
+ console.error({ error: err_1, query: sql, arguments: this.args });
135
131
  throw err_1;
136
132
  case 3: return [2 /*return*/];
137
133
  }
package/src/entity.d.ts CHANGED
@@ -2,39 +2,35 @@ import { Allowed, AllowedForInstance } from "./context";
2
2
  import { FieldMetadata as FieldMetadata } from './column-interfaces';
3
3
  import { EntityOrderBy, FieldsMetadata, EntityFilter, EntityRef } from "./remult3";
4
4
  export interface EntityOptions<entityType = any> {
5
- id?: (entity: FieldsMetadata<entityType>) => FieldMetadata;
6
- /**
7
- * The name of the table in the database that holds the data for this entity.
8
- * If no name is set, the `key` will be used instead.
9
- * @example
10
- * dbName:'myProducts'
11
- */
12
- dbName?: string;
13
- sqlExpression?: string | ((entity: FieldsMetadata<entityType>) => string | Promise<string>);
14
5
  /**A human readable name for the entity */
15
6
  caption?: string;
16
7
  /**
17
8
  * Determines if this Entity is available for get requests using Rest Api
18
- * @see [allowed](http://remult.dev/guide/allowed.html)*/
9
+ * @see [allowed](http://remult.dev/docs/allowed.html)*/
19
10
  allowApiRead?: Allowed;
20
11
  /**
21
12
  * Determines if this entity can be updated through the api.
22
- * @see [allowed](http://remult.dev/guide/allowed.html)*/
13
+ * @see [allowed](http://remult.dev/docs/allowed.html)*/
23
14
  allowApiUpdate?: AllowedForInstance<entityType>;
24
- /** @see [allowed](http://remult.dev/guide/allowed.html)*/
15
+ /** Determines if entries for this entity can be deleted through the api.
16
+ * @see [allowed](http://remult.dev/docs/allowed.html)*/
25
17
  allowApiDelete?: AllowedForInstance<entityType>;
26
- /** @see [allowed](http://remult.dev/guide/allowed.html)*/
18
+ /** Determines if new entries for this entity can be posted through the api.
19
+ * @see [allowed](http://remult.dev/docs/allowed.html)*/
27
20
  allowApiInsert?: AllowedForInstance<entityType>;
28
21
  /** sets the `allowApiUpdate`, `allowApiDelete` and `allowApiInsert` properties in a single set */
29
22
  allowApiCrud?: Allowed;
30
23
  /** A filter that determines which rows can be queries using the api.
31
-
24
+ * @example
25
+ * apiPrefilter: { archive:false }
26
+ *
27
+ * @see [EntityFilter](http://remult.dev/docs/entityFilter.html)
32
28
  */
33
29
  apiPrefilter?: EntityFilter<entityType> | (() => EntityFilter<entityType> | Promise<EntityFilter<entityType>>);
34
- apiRequireId?: Allowed;
35
- /** A filter that will be used for all queries from this entity both from the API and from within the server.
30
+ /** A filter that will be used for all queries from this entity both from the API and from within the backend.
36
31
  * @example
37
- * fixedWhereFilter: () => this.archive.isEqualTo(false)
32
+ * fixedWhereFilter: { archive:false }
33
+ * @see [EntityFilter](http://remult.dev/docs/entityFilter.html)
38
34
  */
39
35
  backendPrefilter?: EntityFilter<entityType> | (() => EntityFilter<entityType> | Promise<EntityFilter<entityType>>);
40
36
  /** An order by to be used, in case no order by was specified
@@ -42,23 +38,18 @@ export interface EntityOptions<entityType = any> {
42
38
  * defaultOrderBy: { name: "asc" }
43
39
  *
44
40
  * @example
45
- * defaultOrderBy: { price: "asc", name: "asc" }
46
- *
47
- * @example
48
41
  * defaultOrderBy: { price: "desc", name: "asc" }
49
42
  */
50
43
  defaultOrderBy?: EntityOrderBy<entityType>;
51
44
  /** An event that will be fired before the Entity will be saved to the database.
52
- * If the `validationError` property of the entity or any of it's columns will be set, the save will be aborted and an exception will be thrown.
45
+ * If the `error` property of the entity's ref or any of it's fields will be set, the save will be aborted and an exception will be thrown.
53
46
  * this is the place to run logic that we want to run in any case before an entity is saved.
54
47
  * @example
55
- * saving: async (self) => {
56
- * if (isBackend()) {
57
- * if (self.isNew()) {
58
- * self.createDate.value = new Date();
59
- * }
60
- * }
61
- * }
48
+ * .@Entity<Task>("tasks", {
49
+ * saving: async task => {
50
+ * task.lastUpdated = new Date()
51
+ * }
52
+ *})
62
53
  */
63
54
  saving?: (row: entityType, proceedWithoutSavingToDb: () => void) => Promise<any> | any;
64
55
  /** will be called after the Entity was saved to the data source. */
@@ -67,6 +58,18 @@ export interface EntityOptions<entityType = any> {
67
58
  deleting?: (row: entityType) => Promise<any> | any;
68
59
  /** Will be called after an Entity is deleted */
69
60
  deleted?: (row: entityType) => Promise<any> | any;
61
+ /** Will be called when the entity is being validated, usually prior to the `saving` event */
70
62
  validation?: (row: entityType, ref: EntityRef<entityType>) => Promise<any> | any;
63
+ /** The name of the table in the database that holds the data for this entity.
64
+ * If no name is set, the `key` will be used instead.
65
+ * @example
66
+ * dbName:'myProducts'
67
+ */
68
+ dbName?: string;
69
+ /** For entities that are based on SQL expressions instead of a physical table or view*/
70
+ sqlExpression?: string | ((entity: FieldsMetadata<entityType>) => string | Promise<string>);
71
+ /** An arrow function that identifies the `id` column to use for this entity */
72
+ id?: (entity: FieldsMetadata<entityType>) => FieldMetadata;
71
73
  entityRefInit?: (ref: EntityRef<entityType>, row: entityType) => void;
74
+ apiRequireId?: Allowed;
72
75
  }
@@ -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;
@@ -249,6 +250,19 @@ export declare class ValueListInfo<T extends ValueListItem> implements ValueConv
249
250
  export declare function getValueList<T>(field: FieldRef<T>): T[];
250
251
  export declare function getValueList<T>(field: FieldMetadata<T>): T[];
251
252
  export declare function getValueList<T>(type: ClassType<T>): T[];
253
+ /**Decorates fields that should be used as fields.
254
+ * for more info see: [Field Types](https://remult.dev/docs/field-types.html)
255
+ *
256
+ * FieldOptions can be set in two ways:
257
+ * @example
258
+ * // as an object
259
+ * .@Fields.string({ includeInApi:false })
260
+ * title='';
261
+ * @example
262
+ * // as an arrow function that receives `remult` as a parameter
263
+ * .@Fields.string((options,remult) => options.includeInApi = true)
264
+ * title='';
265
+ */
252
266
  export declare function Field<entityType = any, valueType = any>(valueType: () => ClassType<valueType>, ...options: (FieldOptions<entityType, valueType> | ((options: FieldOptions<entityType, valueType>, remult: Remult) => void))[]): (target: any, key: any, c?: any) => void;
253
267
  export declare const storableMember: unique symbol;
254
268
  export declare function decorateColumnSettings<valueType>(settings: FieldOptions<any, valueType>, remult: Remult): FieldOptions<any, valueType>;
@@ -260,6 +274,29 @@ export declare type BuildEntityFields<entityType> = {
260
274
  [Properties in keyof Partial<OmitEB<entityType>>]: any;
261
275
  };
262
276
  export declare function BuildEntity<entityType>(c: ClassType<entityType>, key: string, fields: BuildEntityFields<entityType>, ...options: (EntityOptions<entityType> | ((options: EntityOptions<entityType>, remult: Remult) => void))[]): void;
277
+ /**Decorates classes that should be used as entities.
278
+ * Receives a key and an array of EntityOptions.
279
+ * @example
280
+ * import { Entity, Fields } from "remult";
281
+ * @Entity("tasks", {
282
+ * allowApiCrud: true
283
+ * })
284
+ * export class Task {
285
+ * @Fields.uuid()
286
+ * id!: string;
287
+ * @Fields.string()
288
+ * title = '';
289
+ * @Fields.boolean()
290
+ * completed = false;
291
+ * }
292
+ * *EntityOptions can be set in two ways:*
293
+ * @example
294
+ * // as an object
295
+ * .@Entity("tasks",{ allowApiCrud:true })
296
+ * @example
297
+ * // as an arrow function that receives `remult` as a parameter
298
+ * .@Entity("tasks", (options,remult) => options.allowApiCrud = true)
299
+ */
263
300
  export declare function Entity<entityType>(key: string, ...options: (EntityOptions<entityType> | ((options: EntityOptions<entityType>, remult: Remult) => void))[]): (target: any) => any;
264
301
  export declare class EntityBase {
265
302
  get _(): EntityRef<this>;