remult 3.4.0-next.6 → 3.4.0-next.9

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.
@@ -181,7 +181,7 @@ export class SqlDatabase {
181
181
  static async selectToRaw(repo, options, sql) {
182
182
  const r = getRepository(repo);
183
183
  const built = await buildFindSql(r.metadata, await getRepositoryInternals(r)._buildEntityDataProviderFindOptions(options ?? {}), sql?.dbNames ??
184
- (await dbNamesOfWithForceSqlExpression(r.metadata, sql?.wrapIdentifier ?? wrapIdentifierOf(r))), sql?.sqlCommand ?? new myDummySQLCommand(), false, sql?.limitSyntax ?? limitSyntaxRequired, { aliasColumns: true, defaultOrderBy: false });
184
+ (await dbNamesOfWithForceSqlExpression(r.metadata, sql?.wrapIdentifier ?? wrapIdentifierOf(r))), sql?.sqlCommand ?? new myDummySQLCommand(), false, sql?.limitSyntax ?? limitSyntaxRequired, { aliasColumns: true });
185
185
  return {
186
186
  sql: built.select,
187
187
  toResult: (row) => built.toResult((_, alias) => row[alias]),
@@ -353,6 +353,8 @@ class ActualSQLEntityDataProvider {
353
353
  async find(options) {
354
354
  const e = await this.init();
355
355
  const r = this.sql.createCommand();
356
+ if (options && !options.orderBy)
357
+ options.orderBy = Sort.createUniqueSort(this.entity, new Sort());
356
358
  const { select, toResult } = await buildFindSql(this.entity, options, e, r, this.sql._getSourceSql().orderByNullsFirst, (limit, offset) => this.strategy.getLimitSqlSyntax(limit, offset));
357
359
  const result = await r.execute(select);
358
360
  return result.rows.map((y) => toResult((i) => y[result.getColumnKeyInResultForIndexInSelect(i)]));
@@ -560,7 +562,7 @@ export function getRowAfterUpdate(meta, dataProvider, data, id, operation) {
560
562
  });
561
563
  }
562
564
  /** The select that `find` runs, and the mapping of one result row to field values. With `aliasColumns`, every column is aliased through `wrapIdentifier`, so a row can be read by alias as well as by position. */
563
- export async function buildFindSql(entity, options, e, r, orderByNullsFirst, limitSyntax, { aliasColumns = false, defaultOrderBy = true } = {}) {
565
+ export async function buildFindSql(entity, options, e, r, orderByNullsFirst, limitSyntax, { aliasColumns = false } = {}) {
564
566
  const { colKeys, select: columns } = await selectColumns(entity, e, r, options?.select, options?.args, aliasColumns);
565
567
  let select = 'select ' + columns + '\n from ' + e.$entityName;
566
568
  if (options) {
@@ -572,9 +574,6 @@ export async function buildFindSql(entity, options, e, r, orderByNullsFirst, lim
572
574
  if (options.limit) {
573
575
  options.orderBy = Sort.createUniqueSort(entity, options.orderBy);
574
576
  }
575
- if (!options.orderBy && defaultOrderBy) {
576
- options.orderBy = Sort.createUniqueSort(entity, new Sort());
577
- }
578
577
  if (options.orderBy) {
579
578
  let first = true;
580
579
  for (const c of options.orderBy.Segments) {
@@ -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
  ;
@@ -597,7 +597,16 @@ export class RepositoryImplementation {
597
597
  if (this._defaultFindOptions) {
598
598
  options = { ...this._defaultFindOptions, ...options };
599
599
  }
600
- let opt = await this._buildEntityDataProviderFindOptions(options);
600
+ let findOptions = options;
601
+ if ((!findOptions.orderBy || Object.keys(findOptions.orderBy).length === 0) &&
602
+ !this._dataProvider.isProxy &&
603
+ this._info.entityInfo.defaultOrderBy) {
604
+ findOptions = {
605
+ ...findOptions,
606
+ orderBy: this._info.entityInfo.defaultOrderBy,
607
+ };
608
+ }
609
+ let opt = await this._buildEntityDataProviderFindOptions(findOptions);
601
610
  if (skipOrderByAndLimit) {
602
611
  delete opt.orderBy;
603
612
  delete opt.limit;
@@ -633,10 +642,6 @@ export class RepositoryImplementation {
633
642
  return f.key;
634
643
  });
635
644
  }
636
- if (!options.orderBy || Object.keys(options.orderBy).length === 0) {
637
- if (!this._dataProvider.isProxy)
638
- options.orderBy = this._info.entityInfo.defaultOrderBy;
639
- }
640
645
  opt.where = await this._translateWhereToFilter(options.where);
641
646
  if (options.orderBy !== undefined)
642
647
  opt.orderBy = Sort.translateOrderByToSort(this.metadata, options.orderBy);
@@ -2389,6 +2394,9 @@ export function ValueListFieldType(...options) {
2389
2394
  if (ref.value && !values.find((v) => v === ref.value)) {
2390
2395
  ref.value = values.find((v) => v.id === ref.value.id) || ref.value;
2391
2396
  }
2397
+ // A value already stored is a fact. Only a new row or a new value has to be in the list.
2398
+ if (!ref.isNew && !ref.valueChanged())
2399
+ return;
2392
2400
  return Validators.in(values)(entity, ref);
2393
2401
  };
2394
2402
  }, ...options)(type);
@@ -2407,6 +2415,7 @@ export class ValueListInfo {
2407
2415
  byIdMap = new Map();
2408
2416
  values = [];
2409
2417
  isNumeric = false;
2418
+ unknownIdValue;
2410
2419
  constructor(valueListType) {
2411
2420
  this.valueListType = valueListType;
2412
2421
  for (let member in this.valueListType) {
@@ -2427,7 +2436,9 @@ export class ValueListInfo {
2427
2436
  var options = this.valueListType[storableMember];
2428
2437
  if (options) {
2429
2438
  for (const op of options) {
2430
- if (op?.getValues) {
2439
+ if (!op || typeof op === 'function')
2440
+ continue;
2441
+ if (op.getValues) {
2431
2442
  this.values.splice(0, this.values.length, ...op.getValues());
2432
2443
  this.byIdMap.clear();
2433
2444
  this.values.forEach((s) => {
@@ -2435,6 +2446,8 @@ export class ValueListInfo {
2435
2446
  this.byIdMap.set(s.id, s);
2436
2447
  });
2437
2448
  }
2449
+ if ('unknownIdValue' in op)
2450
+ this.unknownIdValue = op.unknownIdValue;
2438
2451
  }
2439
2452
  if (this.values.find((s) => s.id === undefined))
2440
2453
  throw new Error(`ValueType ${this.valueListType} has values without an id`);
@@ -2446,13 +2459,21 @@ export class ValueListInfo {
2446
2459
  getValues() {
2447
2460
  return this.values;
2448
2461
  }
2449
- byId(key) {
2450
- if (this.isNumeric)
2451
- key = +key;
2452
- return this.byIdMap.get(key);
2462
+ /** Declared id only. Pass `useUnknownIdValue` to also apply `unknownIdValue` (`null` and `undefined` still return `undefined`). */
2463
+ byId(key, useUnknownIdValue = false) {
2464
+ const lookupKey = this.isNumeric ? +key : key;
2465
+ const known = this.byIdMap.get(lookupKey);
2466
+ if (known !== undefined || !useUnknownIdValue)
2467
+ return known;
2468
+ if (key == null)
2469
+ return undefined;
2470
+ const fallback = this.unknownIdValue;
2471
+ if (typeof fallback !== 'function')
2472
+ return fallback;
2473
+ return fallback(lookupKey);
2453
2474
  }
2454
2475
  fromJson(val) {
2455
- return this.byId(val);
2476
+ return this.byId(val, true);
2456
2477
  }
2457
2478
  toJson(val) {
2458
2479
  if (!val)
package/esm/src/sort.js CHANGED
@@ -128,9 +128,6 @@ export class Sort {
128
128
  * @returns {Sort} A `Sort` instance representing the unique sort criteria.
129
129
  */
130
130
  static createUniqueSort(entityMetadata, orderBy) {
131
- if ((!orderBy || Object.keys(orderBy).length === 0) &&
132
- entityMetadata.options.defaultOrderBy)
133
- orderBy = Sort.translateOrderByToSort(entityMetadata, entityMetadata.options.defaultOrderBy);
134
131
  if (!orderBy)
135
132
  orderBy = new Sort();
136
133
  for (const field of entityMetadata.idMetadata.fields) {
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.9",
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
@@ -124,9 +124,8 @@ export interface RawSelectOptions {
124
124
  }
125
125
  export declare function getRowAfterUpdate<entityType>(meta: EntityMetadata<entityType>, dataProvider: EntityDataProvider, data: any, id: any, operation: string): any;
126
126
  /** The select that `find` runs, and the mapping of one result row to field values. With `aliasColumns`, every column is aliased through `wrapIdentifier`, so a row can be read by alias as well as by position. */
127
- export declare function buildFindSql(entity: EntityMetadata, options: EntityDataProviderFindOptions | undefined, e: EntityDbNamesBase, r: SqlCommandWithParameters, orderByNullsFirst: boolean | undefined, limitSyntax: (limit: number, offset: number) => string, { aliasColumns, defaultOrderBy }?: {
127
+ export declare function buildFindSql(entity: EntityMetadata, options: EntityDataProviderFindOptions | undefined, e: EntityDbNamesBase, r: SqlCommandWithParameters, orderByNullsFirst: boolean | undefined, limitSyntax: (limit: number, offset: number) => string, { aliasColumns }?: {
128
128
  aliasColumns?: boolean | undefined;
129
- defaultOrderBy?: boolean | undefined;
130
129
  }): Promise<{
131
130
  select: string;
132
131
  colKeys: FieldMetadata<unknown, unknown>[];
@@ -315,7 +315,7 @@ var SqlDatabase = /** @class */ (function () {
315
315
  case 3:
316
316
  _c = (_h.sent());
317
317
  _h.label = 4;
318
- case 4: return [4 /*yield*/, _a.apply(void 0, _b.concat([_c, (_f = sql === null || sql === void 0 ? void 0 : sql.sqlCommand) !== null && _f !== void 0 ? _f : new myDummySQLCommand(), false, (_g = sql === null || sql === void 0 ? void 0 : sql.limitSyntax) !== null && _g !== void 0 ? _g : limitSyntaxRequired, { aliasColumns: true, defaultOrderBy: false }]))];
318
+ case 4: return [4 /*yield*/, _a.apply(void 0, _b.concat([_c, (_f = sql === null || sql === void 0 ? void 0 : sql.sqlCommand) !== null && _f !== void 0 ? _f : new myDummySQLCommand(), false, (_g = sql === null || sql === void 0 ? void 0 : sql.limitSyntax) !== null && _g !== void 0 ? _g : limitSyntaxRequired, { aliasColumns: true }]))];
319
319
  case 5:
320
320
  built = _h.sent();
321
321
  return [2 /*return*/, {
@@ -548,6 +548,8 @@ var ActualSQLEntityDataProvider = /** @class */ (function () {
548
548
  case 1:
549
549
  e = _b.sent();
550
550
  r = this.sql.createCommand();
551
+ if (options && !options.orderBy)
552
+ options.orderBy = sort_js_1.Sort.createUniqueSort(this.entity, new sort_js_1.Sort());
551
553
  return [4 /*yield*/, buildFindSql(this.entity, options, e, r, this.sql._getSourceSql().orderByNullsFirst, function (limit, offset) { return _this.strategy.getLimitSqlSyntax(limit, offset); })];
552
554
  case 2:
553
555
  _a = _b.sent(), select = _a.select, toResult = _a.toResult;
@@ -918,12 +920,12 @@ function buildFindSql(entity_1, options_1, e_8, r_1, orderByNullsFirst_1, limitS
918
920
  return tslib_1.__awaiter(this, arguments, void 0, function (entity, options, e, r, orderByNullsFirst, limitSyntax, _a) {
919
921
  var _b, colKeys, columns, select, where, _c, first, _d, _e, c, _f, _g, e_9_1, page;
920
922
  var e_9, _h;
921
- var _j = _a === void 0 ? {} : _a, _k = _j.aliasColumns, aliasColumns = _k === void 0 ? false : _k, _l = _j.defaultOrderBy, defaultOrderBy = _l === void 0 ? true : _l;
922
- return tslib_1.__generator(this, function (_m) {
923
- switch (_m.label) {
923
+ var _j = _a === void 0 ? {} : _a, _k = _j.aliasColumns, aliasColumns = _k === void 0 ? false : _k;
924
+ return tslib_1.__generator(this, function (_l) {
925
+ switch (_l.label) {
924
926
  case 0: return [4 /*yield*/, selectColumns(entity, e, r, options === null || options === void 0 ? void 0 : options.select, options === null || options === void 0 ? void 0 : options.args, aliasColumns)];
925
927
  case 1:
926
- _b = _m.sent(), colKeys = _b.colKeys, columns = _b.select;
928
+ _b = _l.sent(), colKeys = _b.colKeys, columns = _b.select;
927
929
  select = 'select ' + columns + '\n from ' + e.$entityName;
928
930
  if (!options) return [3 /*break*/, 14];
929
931
  if (!options.where) return [3 /*break*/, 3];
@@ -932,22 +934,19 @@ function buildFindSql(entity_1, options_1, e_8, r_1, orderByNullsFirst_1, limitS
932
934
  _c = select;
933
935
  return [4 /*yield*/, where.resolveWhere()];
934
936
  case 2:
935
- select = _c + _m.sent();
936
- _m.label = 3;
937
+ select = _c + _l.sent();
938
+ _l.label = 3;
937
939
  case 3:
938
940
  if (options.limit) {
939
941
  options.orderBy = sort_js_1.Sort.createUniqueSort(entity, options.orderBy);
940
942
  }
941
- if (!options.orderBy && defaultOrderBy) {
942
- options.orderBy = sort_js_1.Sort.createUniqueSort(entity, new sort_js_1.Sort());
943
- }
944
943
  if (!options.orderBy) return [3 /*break*/, 13];
945
944
  first = true;
946
- _m.label = 4;
945
+ _l.label = 4;
947
946
  case 4:
948
- _m.trys.push([4, 11, 12, 13]);
947
+ _l.trys.push([4, 11, 12, 13]);
949
948
  _d = tslib_1.__values(options.orderBy.Segments), _e = _d.next();
950
- _m.label = 5;
949
+ _l.label = 5;
951
950
  case 5:
952
951
  if (!!_e.done) return [3 /*break*/, 10];
953
952
  c = _e.value;
@@ -963,8 +962,8 @@ function buildFindSql(entity_1, options_1, e_8, r_1, orderByNullsFirst_1, limitS
963
962
  return [3 /*break*/, 8];
964
963
  case 6: return [4 /*yield*/, e.$dbNameOf(c.field)];
965
964
  case 7:
966
- _g = _m.sent();
967
- _m.label = 8;
965
+ _g = _l.sent();
966
+ _l.label = 8;
968
967
  case 8:
969
968
  select = _f + _g;
970
969
  if (c.isDescending)
@@ -975,13 +974,13 @@ function buildFindSql(entity_1, options_1, e_8, r_1, orderByNullsFirst_1, limitS
975
974
  else
976
975
  select += ' nulls first';
977
976
  }
978
- _m.label = 9;
977
+ _l.label = 9;
979
978
  case 9:
980
979
  _e = _d.next();
981
980
  return [3 /*break*/, 5];
982
981
  case 10: return [3 /*break*/, 13];
983
982
  case 11:
984
- e_9_1 = _m.sent();
983
+ e_9_1 = _l.sent();
985
984
  e_9 = { error: e_9_1 };
986
985
  return [3 /*break*/, 13];
987
986
  case 12:
@@ -999,7 +998,7 @@ function buildFindSql(entity_1, options_1, e_8, r_1, orderByNullsFirst_1, limitS
999
998
  page = 1;
1000
999
  select += ' ' + limitSyntax(options.limit, (page - 1) * options.limit);
1001
1000
  }
1002
- _m.label = 14;
1001
+ _l.label = 14;
1003
1002
  case 14: return [2 /*return*/, {
1004
1003
  select: select,
1005
1004
  colKeys: colKeys,
@@ -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`. Only `null` and `undefined` stay `undefined`; a blank `''` uses this, which is the usual legacy column. A declared id of `''` is unaffected. @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,9 +311,11 @@ 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
- byId(key: any): T | undefined;
317
+ /** Declared id only. Pass `useUnknownIdValue` to also apply `unknownIdValue` (`null` and `undefined` still return `undefined`). */
318
+ byId(key: any, useUnknownIdValue?: boolean): T | undefined;
315
319
  fromJson(val: any): T;
316
320
  toJson(val: T): any;
317
321
  fromDb(val: any): T;
@@ -954,7 +954,7 @@ var RepositoryImplementation = /** @class */ (function () {
954
954
  };
955
955
  RepositoryImplementation.prototype._rawFind = function (options_1) {
956
956
  return tslib_1.__awaiter(this, arguments, void 0, function (options, skipOrderByAndLimit, loader, actualFind) {
957
- var opt, rawRows, result;
957
+ var findOptions, opt, rawRows, result;
958
958
  if (skipOrderByAndLimit === void 0) { skipOrderByAndLimit = false; }
959
959
  return tslib_1.__generator(this, function (_a) {
960
960
  switch (_a.label) {
@@ -964,7 +964,13 @@ var RepositoryImplementation = /** @class */ (function () {
964
964
  if (this._defaultFindOptions) {
965
965
  options = tslib_1.__assign(tslib_1.__assign({}, this._defaultFindOptions), options);
966
966
  }
967
- return [4 /*yield*/, this._buildEntityDataProviderFindOptions(options)];
967
+ findOptions = options;
968
+ if ((!findOptions.orderBy || Object.keys(findOptions.orderBy).length === 0) &&
969
+ !this._dataProvider.isProxy &&
970
+ this._info.entityInfo.defaultOrderBy) {
971
+ findOptions = tslib_1.__assign(tslib_1.__assign({}, findOptions), { orderBy: this._info.entityInfo.defaultOrderBy });
972
+ }
973
+ return [4 /*yield*/, this._buildEntityDataProviderFindOptions(findOptions)];
968
974
  case 1:
969
975
  opt = _a.sent();
970
976
  if (skipOrderByAndLimit) {
@@ -1029,10 +1035,6 @@ var RepositoryImplementation = /** @class */ (function () {
1029
1035
  return f.key;
1030
1036
  });
1031
1037
  }
1032
- if (!options.orderBy || Object.keys(options.orderBy).length === 0) {
1033
- if (!this._dataProvider.isProxy)
1034
- options.orderBy = this._info.entityInfo.defaultOrderBy;
1035
- }
1036
1038
  _a = opt;
1037
1039
  return [4 /*yield*/, this._translateWhereToFilter(options.where)];
1038
1040
  case 1:
@@ -3970,6 +3972,9 @@ function ValueListFieldType() {
3970
3972
  if (ref.value && !values.find(function (v) { return v === ref.value; })) {
3971
3973
  ref.value = values.find(function (v) { return v.id === ref.value.id; }) || ref.value;
3972
3974
  }
3975
+ // A value already stored is a fact. Only a new row or a new value has to be in the list.
3976
+ if (!ref.isNew && !ref.valueChanged())
3977
+ return;
3973
3978
  return validators_js_1.Validators.in(values)(entity, ref);
3974
3979
  };
3975
3980
  }], tslib_1.__read(options), false))(type);
@@ -4003,7 +4008,9 @@ var ValueListInfo = /** @class */ (function () {
4003
4008
  try {
4004
4009
  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
4010
  var op = options_1_1.value;
4006
- if (op === null || op === void 0 ? void 0 : op.getValues) {
4011
+ if (!op || typeof op === 'function')
4012
+ continue;
4013
+ if (op.getValues) {
4007
4014
  (_b = this.values).splice.apply(_b, tslib_1.__spreadArray([0, this.values.length], tslib_1.__read(op.getValues()), false));
4008
4015
  this.byIdMap.clear();
4009
4016
  this.values.forEach(function (s) {
@@ -4011,6 +4018,8 @@ var ValueListInfo = /** @class */ (function () {
4011
4018
  _this.byIdMap.set(s.id, s);
4012
4019
  });
4013
4020
  }
4021
+ if ('unknownIdValue' in op)
4022
+ this.unknownIdValue = op.unknownIdValue;
4014
4023
  }
4015
4024
  }
4016
4025
  catch (e_54_1) { e_54 = { error: e_54_1 }; }
@@ -4038,13 +4047,22 @@ var ValueListInfo = /** @class */ (function () {
4038
4047
  ValueListInfo.prototype.getValues = function () {
4039
4048
  return this.values;
4040
4049
  };
4041
- ValueListInfo.prototype.byId = function (key) {
4042
- if (this.isNumeric)
4043
- key = +key;
4044
- return this.byIdMap.get(key);
4050
+ /** Declared id only. Pass `useUnknownIdValue` to also apply `unknownIdValue` (`null` and `undefined` still return `undefined`). */
4051
+ ValueListInfo.prototype.byId = function (key, useUnknownIdValue) {
4052
+ if (useUnknownIdValue === void 0) { useUnknownIdValue = false; }
4053
+ var lookupKey = this.isNumeric ? +key : key;
4054
+ var known = this.byIdMap.get(lookupKey);
4055
+ if (known !== undefined || !useUnknownIdValue)
4056
+ return known;
4057
+ if (key == null)
4058
+ return undefined;
4059
+ var fallback = this.unknownIdValue;
4060
+ if (typeof fallback !== 'function')
4061
+ return fallback;
4062
+ return fallback(lookupKey);
4045
4063
  };
4046
4064
  ValueListInfo.prototype.fromJson = function (val) {
4047
- return this.byId(val);
4065
+ return this.byId(val, true);
4048
4066
  };
4049
4067
  ValueListInfo.prototype.toJson = function (val) {
4050
4068
  if (!val)
package/src/sort.js CHANGED
@@ -159,9 +159,6 @@ var Sort = /** @class */ (function () {
159
159
  */
160
160
  Sort.createUniqueSort = function (entityMetadata, orderBy) {
161
161
  var e_3, _a;
162
- if ((!orderBy || Object.keys(orderBy).length === 0) &&
163
- entityMetadata.options.defaultOrderBy)
164
- orderBy = Sort.translateOrderByToSort(entityMetadata, entityMetadata.options.defaultOrderBy);
165
162
  if (!orderBy)
166
163
  orderBy = new Sort();
167
164
  var _loop_2 = function (field) {