remult 3.4.0-next.6 → 3.4.0-next.7

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.
@@ -190,7 +190,12 @@ export class Fields {
190
190
  */
191
191
  static literal(optionalValues, ...options) {
192
192
  return Fields.string({
193
- validate: (entity, event) => Validators.in(optionalValues())(entity, event),
193
+ validate: (entity, event) => {
194
+ // A value already stored is a fact. Only a new row or a new value has to be in the list.
195
+ if (!event.isNew && !event.valueChanged())
196
+ return;
197
+ return Validators.in(optionalValues())(entity, event);
198
+ },
194
199
  //@ts-expect-error as we are adding this to options without it being defined in options
195
200
  [fieldOptionalValuesFunctionKey]: optionalValues,
196
201
  }, ...options);
@@ -200,7 +205,12 @@ export class Fields {
200
205
  return Field(
201
206
  //@ts-ignore
202
207
  () => enumType(), {
203
- validate: (entity, event) => Validators.enum(enumType())(entity, event),
208
+ validate: (entity, event) => {
209
+ // A value already stored is a fact. Only a new row or a new value has to be in the enum.
210
+ if (!event.isNew && !event.valueChanged())
211
+ return;
212
+ return Validators.enum(enumType())(entity, event);
213
+ },
204
214
  [fieldOptionalValuesFunctionKey]: () => getEnumValues(enumType()),
205
215
  }, ...options, (options) => {
206
216
  ;
@@ -2389,6 +2389,9 @@ export function ValueListFieldType(...options) {
2389
2389
  if (ref.value && !values.find((v) => v === ref.value)) {
2390
2390
  ref.value = values.find((v) => v.id === ref.value.id) || ref.value;
2391
2391
  }
2392
+ // A value already stored is a fact. Only a new row or a new value has to be in the list.
2393
+ if (!ref.isNew && !ref.valueChanged())
2394
+ return;
2392
2395
  return Validators.in(values)(entity, ref);
2393
2396
  };
2394
2397
  }, ...options)(type);
@@ -2407,6 +2410,7 @@ export class ValueListInfo {
2407
2410
  byIdMap = new Map();
2408
2411
  values = [];
2409
2412
  isNumeric = false;
2413
+ unknownIdValue;
2410
2414
  constructor(valueListType) {
2411
2415
  this.valueListType = valueListType;
2412
2416
  for (let member in this.valueListType) {
@@ -2427,7 +2431,9 @@ export class ValueListInfo {
2427
2431
  var options = this.valueListType[storableMember];
2428
2432
  if (options) {
2429
2433
  for (const op of options) {
2430
- if (op?.getValues) {
2434
+ if (!op || typeof op === 'function')
2435
+ continue;
2436
+ if (op.getValues) {
2431
2437
  this.values.splice(0, this.values.length, ...op.getValues());
2432
2438
  this.byIdMap.clear();
2433
2439
  this.values.forEach((s) => {
@@ -2435,6 +2441,8 @@ export class ValueListInfo {
2435
2441
  this.byIdMap.set(s.id, s);
2436
2442
  });
2437
2443
  }
2444
+ if ('unknownIdValue' in op)
2445
+ this.unknownIdValue = op.unknownIdValue;
2438
2446
  }
2439
2447
  if (this.values.find((s) => s.id === undefined))
2440
2448
  throw new Error(`ValueType ${this.valueListType} has values without an id`);
@@ -2452,7 +2460,15 @@ export class ValueListInfo {
2452
2460
  return this.byIdMap.get(key);
2453
2461
  }
2454
2462
  fromJson(val) {
2455
- return this.byId(val);
2463
+ const known = this.byId(val);
2464
+ if (known !== undefined)
2465
+ return known;
2466
+ if (val == null)
2467
+ return undefined;
2468
+ const fallback = this.unknownIdValue;
2469
+ if (typeof fallback !== 'function')
2470
+ return fallback;
2471
+ return fallback(this.isNumeric ? +val : val);
2456
2472
  }
2457
2473
  toJson(val) {
2458
2474
  if (!val)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remult",
3
- "version": "3.4.0-next.6",
3
+ "version": "3.4.0-next.7",
4
4
  "description": "A CRUD framework for full-stack TypeScript",
5
5
  "homepage": "https://remult.dev",
6
6
  "repository": {
@@ -58,7 +58,11 @@ export interface FieldOptions<entityType = unknown, valueType = unknown> {
58
58
  * @type {AllowedForInstance<entityType>}
59
59
  */
60
60
  allowApiUpdate?: AllowedForInstance<entityType>;
61
- /** An arrow function that'll be used to perform validations on it
61
+ /** An arrow function that'll be used to perform validations on it.
62
+ *
63
+ * `validate` from several option objects is additive: each one is appended.
64
+ * A function option is the only way to replace validators already set, including a built-in one:
65
+ * `(options) => { options.validate = ... }`.
62
66
  * @example
63
67
  * @Fields.string({
64
68
  * validate: Validators.required
@@ -247,6 +247,9 @@ var Fields = /** @class */ (function () {
247
247
  }
248
248
  return Fields.string.apply(Fields, tslib_1.__spreadArray([(_a = {
249
249
  validate: function (entity, event) {
250
+ // A value already stored is a fact. Only a new row or a new value has to be in the list.
251
+ if (!event.isNew && !event.valueChanged())
252
+ return;
250
253
  return validators_js_1.Validators.in(optionalValues())(entity, event);
251
254
  }
252
255
  },
@@ -265,6 +268,9 @@ var Fields = /** @class */ (function () {
265
268
  //@ts-ignore
266
269
  function () { return enumType(); }, (_a = {
267
270
  validate: function (entity, event) {
271
+ // A value already stored is a fact. Only a new row or a new value has to be in the enum.
272
+ if (!event.isNew && !event.valueChanged())
273
+ return;
268
274
  return validators_js_1.Validators.enum(enumType())(entity, event);
269
275
  }
270
276
  },
@@ -302,6 +302,8 @@ export declare function isAutoIncrement(f: FieldMetadata): boolean;
302
302
  export declare function ValueListFieldType<valueType extends ValueListItem = ValueListItem>(...options: (ValueListFieldOptions<any, valueType> | ((options: FieldOptions<any, valueType>, remult: Remult) => void))[]): (type: ClassType<valueType>, context?: any) => void;
303
303
  export interface ValueListFieldOptions<entityType, valueType> extends FieldOptions<entityType, valueType> {
304
304
  getValues?: () => valueType[];
305
+ /** Value used when a stored id is not in the list. A value, or `(id) => value`. @default undefined */
306
+ unknownIdValue?: valueType | ((id: any) => valueType | undefined);
305
307
  }
306
308
  export declare class ValueListInfo<T extends ValueListItem> implements ValueConverter<T> {
307
309
  private valueListType;
@@ -309,6 +311,7 @@ export declare class ValueListInfo<T extends ValueListItem> implements ValueConv
309
311
  private byIdMap;
310
312
  private values;
311
313
  isNumeric: boolean;
314
+ private unknownIdValue?;
312
315
  private constructor();
313
316
  getValues(): T[];
314
317
  byId(key: any): T | undefined;
@@ -3970,6 +3970,9 @@ function ValueListFieldType() {
3970
3970
  if (ref.value && !values.find(function (v) { return v === ref.value; })) {
3971
3971
  ref.value = values.find(function (v) { return v.id === ref.value.id; }) || ref.value;
3972
3972
  }
3973
+ // A value already stored is a fact. Only a new row or a new value has to be in the list.
3974
+ if (!ref.isNew && !ref.valueChanged())
3975
+ return;
3973
3976
  return validators_js_1.Validators.in(values)(entity, ref);
3974
3977
  };
3975
3978
  }], tslib_1.__read(options), false))(type);
@@ -4003,7 +4006,9 @@ var ValueListInfo = /** @class */ (function () {
4003
4006
  try {
4004
4007
  for (var options_1 = tslib_1.__values(options), options_1_1 = options_1.next(); !options_1_1.done; options_1_1 = options_1.next()) {
4005
4008
  var op = options_1_1.value;
4006
- if (op === null || op === void 0 ? void 0 : op.getValues) {
4009
+ if (!op || typeof op === 'function')
4010
+ continue;
4011
+ if (op.getValues) {
4007
4012
  (_b = this.values).splice.apply(_b, tslib_1.__spreadArray([0, this.values.length], tslib_1.__read(op.getValues()), false));
4008
4013
  this.byIdMap.clear();
4009
4014
  this.values.forEach(function (s) {
@@ -4011,6 +4016,8 @@ var ValueListInfo = /** @class */ (function () {
4011
4016
  _this.byIdMap.set(s.id, s);
4012
4017
  });
4013
4018
  }
4019
+ if ('unknownIdValue' in op)
4020
+ this.unknownIdValue = op.unknownIdValue;
4014
4021
  }
4015
4022
  }
4016
4023
  catch (e_54_1) { e_54 = { error: e_54_1 }; }
@@ -4044,7 +4051,15 @@ var ValueListInfo = /** @class */ (function () {
4044
4051
  return this.byIdMap.get(key);
4045
4052
  };
4046
4053
  ValueListInfo.prototype.fromJson = function (val) {
4047
- return this.byId(val);
4054
+ var known = this.byId(val);
4055
+ if (known !== undefined)
4056
+ return known;
4057
+ if (val == null)
4058
+ return undefined;
4059
+ var fallback = this.unknownIdValue;
4060
+ if (typeof fallback !== 'function')
4061
+ return fallback;
4062
+ return fallback(this.isNumeric ? +val : val);
4048
4063
  };
4049
4064
  ValueListInfo.prototype.toJson = function (val) {
4050
4065
  if (!val)