remult 0.23.0-exp.2 → 0.23.0-exp.21

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.
Files changed (92) hide show
  1. package/README.md +26 -27
  2. package/esm/graphql.js +7 -1
  3. package/esm/index.d.ts +16 -3
  4. package/esm/index.js +17 -2
  5. package/esm/internals.d.ts +2 -1
  6. package/esm/internals.js +1 -1
  7. package/esm/remult-express.js +1 -1
  8. package/esm/remult-knex/index.js +2 -1
  9. package/esm/remult-mongo.js +2 -1
  10. package/esm/server/JsonEntityFileStorage.js +1 -1
  11. package/esm/server/expressBridge.js +1 -1
  12. package/esm/src/CompoundIdField.d.ts +1 -1
  13. package/esm/src/CompoundIdField.js +3 -1
  14. package/esm/src/buildRestDataProvider.d.ts +1 -2
  15. package/esm/src/column-interfaces.d.ts +19 -7
  16. package/esm/src/column.d.ts +4 -18
  17. package/esm/src/column.js +10 -44
  18. package/esm/src/context.d.ts +1 -1
  19. package/esm/src/context.js +5 -1
  20. package/esm/src/data-interfaces.js +1 -2
  21. package/esm/src/data-providers/array-entity-data-provider.d.ts +1 -1
  22. package/esm/src/data-providers/array-entity-data-provider.js +6 -6
  23. package/esm/src/data-providers/sql-database.js +2 -1
  24. package/esm/src/data-providers/web-sql-data-provider.js +3 -3
  25. package/esm/src/entity.d.ts +48 -17
  26. package/esm/src/filter/filter-interfaces.d.ts +2 -16
  27. package/esm/src/filter/filter-interfaces.js +87 -6
  28. package/esm/src/live-query/LiveQueryClient.js +2 -1
  29. package/esm/src/live-query/SubscriptionChannel.js +4 -3
  30. package/esm/src/remult-proxy.js +10 -2
  31. package/esm/src/remult3/Fields.d.ts +140 -21
  32. package/esm/src/remult3/Fields.js +26 -30
  33. package/esm/src/remult3/RepositoryImplementation.d.ts +10 -16
  34. package/esm/src/remult3/RepositoryImplementation.js +165 -48
  35. package/esm/src/remult3/entity.d.ts +1 -1
  36. package/esm/src/remult3/entity.js +0 -1
  37. package/esm/src/remult3/getEntityRef.d.ts +1 -1
  38. package/esm/src/remult3/getEntityRef.js +1 -1
  39. package/esm/src/remult3/relation-loader.js +4 -1
  40. package/esm/src/remult3/remult3.d.ts +132 -7
  41. package/esm/src/remult3/remult3.js +30 -0
  42. package/esm/src/remult3/repository-internals.d.ts +14 -0
  43. package/esm/src/remult3/repository-internals.js +7 -0
  44. package/esm/src/server-action.js +1 -1
  45. package/esm/src/sort.d.ts +3 -3
  46. package/esm/src/sort.js +36 -8
  47. package/graphql.js +10 -2
  48. package/index.d.ts +16 -3
  49. package/index.js +19 -3
  50. package/internals.d.ts +2 -1
  51. package/internals.js +3 -1
  52. package/package.json +1 -1
  53. package/remult-express.js +1 -1
  54. package/remult-knex/index.js +2 -1
  55. package/remult-mongo.js +2 -1
  56. package/server/JsonEntityFileStorage.js +1 -1
  57. package/server/expressBridge.js +1 -1
  58. package/src/CompoundIdField.d.ts +1 -1
  59. package/src/CompoundIdField.js +3 -0
  60. package/src/buildRestDataProvider.d.ts +1 -2
  61. package/src/column-interfaces.d.ts +19 -7
  62. package/src/column.d.ts +4 -18
  63. package/src/column.js +10 -56
  64. package/src/context.d.ts +1 -1
  65. package/src/context.js +5 -1
  66. package/src/data-interfaces.js +1 -2
  67. package/src/data-providers/array-entity-data-provider.d.ts +1 -1
  68. package/src/data-providers/array-entity-data-provider.js +5 -6
  69. package/src/data-providers/sql-database.js +2 -1
  70. package/src/data-providers/web-sql-data-provider.js +3 -3
  71. package/src/entity.d.ts +48 -17
  72. package/src/filter/filter-interfaces.d.ts +2 -16
  73. package/src/filter/filter-interfaces.js +101 -9
  74. package/src/live-query/LiveQueryClient.js +2 -1
  75. package/src/live-query/SubscriptionChannel.js +4 -3
  76. package/src/remult-proxy.js +43 -29
  77. package/src/remult3/Fields.d.ts +140 -21
  78. package/src/remult3/Fields.js +32 -32
  79. package/src/remult3/RepositoryImplementation.d.ts +10 -16
  80. package/src/remult3/RepositoryImplementation.js +286 -163
  81. package/src/remult3/entity.d.ts +1 -1
  82. package/src/remult3/entity.js +0 -1
  83. package/src/remult3/getEntityRef.d.ts +1 -1
  84. package/src/remult3/getEntityRef.js +2 -1
  85. package/src/remult3/relation-loader.js +4 -1
  86. package/src/remult3/remult3.d.ts +132 -7
  87. package/src/remult3/remult3.js +30 -0
  88. package/src/remult3/repository-internals.d.ts +14 -0
  89. package/src/remult3/repository-internals.js +11 -0
  90. package/src/server-action.js +1 -1
  91. package/src/sort.d.ts +3 -3
  92. package/src/sort.js +43 -11
@@ -1,6 +1,6 @@
1
1
  import type { Remult } from '../context';
2
2
  import type { EntityOptions } from '../entity';
3
- import type { ClassDecoratorContextStub } from './RepositoryImplementation';
3
+ import type { ClassDecoratorContextStub } from './remult3';
4
4
  /**Decorates classes that should be used as entities.
5
5
  * Receives a key and an array of EntityOptions.
6
6
  * @example
@@ -4,7 +4,6 @@ exports.Entity = void 0;
4
4
  var tslib_1 = require("tslib");
5
5
  var context_1 = require("../context");
6
6
  var getEntityRef_1 = require("./getEntityRef");
7
- //[ ] YONI - in Typescript 5 I do get the name of the class, what would we like to change because of that?
8
7
  /**Decorates classes that should be used as entities.
9
8
  * Receives a key and an array of EntityOptions.
10
9
  * @example
@@ -5,5 +5,5 @@ export declare function getEntityRef<entityType>(entity: entityType, throwExcept
5
5
  export declare const entityMember: unique symbol;
6
6
  export declare const entityInfo: unique symbol;
7
7
  export declare const entityInfo_key: unique symbol;
8
- export declare function getEntitySettings<T>(entity: ClassType<T>, throwError?: boolean): EntityOptionsFactory;
8
+ export declare function getEntitySettings<T>(entity: ClassType<T>, throwError?: boolean): EntityOptionsFactory | undefined;
9
9
  export declare function getEntityKey(entity: ClassType<any>): string;
@@ -2,11 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getEntityKey = exports.getEntitySettings = exports.entityInfo_key = exports.entityInfo = exports.entityMember = exports.getEntityRef = void 0;
4
4
  function getEntityRef(entity, throwException) {
5
+ var _a;
5
6
  if (throwException === void 0) { throwException = true; }
6
7
  var x = entity[exports.entityMember];
7
8
  if (!x && throwException)
8
9
  throw new Error('item ' +
9
- entity.constructor.name +
10
+ (((_a = entity.constructor) === null || _a === void 0 ? void 0 : _a.name) || entity) +
10
11
  ' was not initialized using a context');
11
12
  return x;
12
13
  }
@@ -96,7 +96,10 @@ var QueryVariation = /** @class */ (function () {
96
96
  var w = this.whereVariations.get(whereKey);
97
97
  if (!w) {
98
98
  var keys = Object.keys(where);
99
- if (keys.length === 1 && typeof where[keys[0]] !== 'object') {
99
+ if (keys.length === 1 &&
100
+ typeof where[keys[0]] !== 'object' &&
101
+ !findOptions.limit // because merging calls in that case may bring non more rows than the limit
102
+ ) {
100
103
  var inVariation = this.pendingInStatements.get(keys[0]);
101
104
  if (!inVariation) {
102
105
  this.pendingInStatements.set(keys[0], (inVariation = new PendingInStatements(this.rel, keys[0], findOptions)));
@@ -23,11 +23,56 @@ export interface EntityRef<entityType> extends Subscribable {
23
23
  metadata: EntityMetadata<entityType>;
24
24
  toApiJson(): any;
25
25
  validate(): Promise<ErrorInfo<entityType> | undefined>;
26
+ relations: RepositoryRelations<entityType>;
26
27
  readonly apiUpdateAllowed: boolean;
27
28
  readonly apiDeleteAllowed: boolean;
28
29
  readonly apiInsertAllowed: boolean;
29
30
  readonly isLoading: boolean;
30
31
  }
32
+ /**
33
+ * Represents a lifecycle event associated with an entity instance. These events
34
+ * are triggered during various stages of the entity's lifecycle, such as validation,
35
+ * saving, saved, deleting, and deleted.
36
+ *
37
+ * @template entityType The type of the entity associated with the event.
38
+ * @see [Entity Lifecycle Hooks](http://remult.dev/docs/lifecycle-hooks)
39
+ */
40
+ export interface LifecycleEvent<entityType> {
41
+ /**
42
+ * Indicates whether the entity is new or existing.
43
+ */
44
+ isNew: boolean;
45
+ /**
46
+ * A reference to the fields of the entity, providing access to its properties.
47
+ */
48
+ fields: FieldsRef<entityType>;
49
+ /**
50
+ * The ID of the entity.
51
+ */
52
+ id: idType<entityType>;
53
+ /**
54
+ * The original ID of the entity, useful for tracking changes.
55
+ */
56
+ originalId: idType<entityType>;
57
+ /**
58
+ * The repository associated with the entity, providing access to repository methods.
59
+ */
60
+ repository: Repository<entityType>;
61
+ /**
62
+ * Metadata describing the entity's structure and configuration.
63
+ */
64
+ metadata: EntityMetadata<entityType>;
65
+ /**
66
+ * A function that can be used to prevent the default behavior associated with
67
+ * the lifecycle event.
68
+ */
69
+ preventDefault: VoidFunction;
70
+ /**
71
+ * A reference to the repository relations associated with the entity, providing
72
+ * access to related entities and their data.
73
+ */
74
+ relations: RepositoryRelations<entityType>;
75
+ }
31
76
  export interface ControllerRef<entityType> extends Subscribable {
32
77
  hasErrors(): boolean;
33
78
  fields: FieldsRef<entityType>;
@@ -44,7 +89,7 @@ export interface Subscribable {
44
89
  subscribe(listener: RefSubscriber): Unsubscribe;
45
90
  }
46
91
  export type FieldsRef<entityType> = {
47
- [Properties in keyof OmitEB<entityType>]: entityType[Properties] extends {
92
+ [Properties in keyof OmitEB<entityType>]: NonNullable<entityType[Properties]> extends {
48
93
  id?: number | string;
49
94
  } ? IdFieldRef<entityType, entityType[Properties]> : FieldRef<entityType, entityType[Properties]>;
50
95
  } & {
@@ -301,7 +346,7 @@ export declare type EntityOrderBy<entityType> = {
301
346
  export declare type EntityFilter<entityType> = {
302
347
  [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 {
303
348
  id?: string | number;
304
- } | undefined ? IdFilter<Partial<OmitEB<entityType>>[Properties]> : ValueFilter<Partial<OmitEB<entityType>>[Properties]>) & ContainsStringValueFilter;
349
+ } | undefined ? IdFilter<Partial<OmitEB<entityType>>[Properties]> : ValueFilter<Partial<OmitEB<entityType>>[Properties]>) | ContainsStringValueFilter;
305
350
  } & {
306
351
  $or?: EntityFilter<entityType>[];
307
352
  $and?: EntityFilter<entityType>[];
@@ -331,7 +376,46 @@ export type IdFilter<valueType> = ValueFilter<valueType> | {
331
376
  } ? number : string>;
332
377
  };
333
378
  export interface LoadOptions<entityType> {
379
+ /**
380
+ * @deprecated The 'load' option is deprecated and will be removed in future versions.
381
+ * Use 'Relations.toOne' along with the 'include' option instead.
382
+ *
383
+ * Example usage:
384
+ * ```
385
+ * // Deprecated usage with 'load' option
386
+ * await remult.repo(Order).find({
387
+ * load: (o) => [o.customer],
388
+ * });
389
+ *
390
+ *
391
+ * // Preferred usage with 'Relations.toOne' and 'include' option
392
+ * await remult.repo(Order).find({
393
+ * include: { customer: true },
394
+ * });
395
+ * ```
396
+ */
334
397
  load?: (entity: FieldsMetadata<entityType>) => FieldMetadata[];
398
+ /**
399
+ * An option used in the `find` and `findFirst` methods to specify which related entities should be included
400
+ * when querying the source entity. It allows you to eagerly load related data to avoid N+1 query problems.
401
+ *
402
+ * @param include An object specifying the related entities to include, their options, and filtering criteria.
403
+ *
404
+ * Example usage:
405
+ * ```
406
+ * const orders = await customerRepo.find({
407
+ * include: {
408
+ * // Include the 'tags' relation for each customer.
409
+ * tags: true,
410
+ * },
411
+ * });
412
+ * ```
413
+ * In this example, the `tags` relation for each customer will be loaded and included in the query result.
414
+ *
415
+ * @see {@link Relations.toMany}
416
+ * @see {@link Relations.toOne}
417
+ * @see {@link RelationOptions}
418
+ */
335
419
  include?: MembersToInclude<entityType>;
336
420
  }
337
421
  export interface FindOptionsBase<entityType> extends LoadOptions<entityType> {
@@ -402,26 +486,67 @@ export interface RelationInfo {
402
486
  toType: () => any;
403
487
  type: 'reference' | 'toOne' | 'toMany';
404
488
  }
489
+ /**
490
+ * Options for configuring a relation between entities.
491
+ *
492
+ * @template fromEntity The type of the source entity (the entity defining the relation).
493
+ * @template toEntity The type of the target entity (the related entity).
494
+ * @template matchIdEntity The type used for matching IDs in the relation.
495
+ * @template optionsType The type of find options to apply to the relation (default is FindOptionsBase<toEntity>).
496
+ */
405
497
  export type RelationOptions<fromEntity, toEntity, matchIdEntity, optionsType extends FindOptionsBase<toEntity> = FindOptionsBase<toEntity>> = {
498
+ /**
499
+ * An object specifying custom field names for the relation.
500
+ * Each key represents a field in the related entity, and its value is the corresponding field in the source entity.
501
+ * For example, `{ customerId: 'id' }` maps the 'customerId' field in the related entity to the 'id' field in the source entity.
502
+ * This is useful when you want to define custom field mappings for the relation.
503
+ */
406
504
  fields?: {
407
505
  [K in keyof toEntity]?: keyof fromEntity;
408
506
  };
507
+ /**
508
+ * The name of the field for this relation.
509
+ */
409
510
  field?: keyof matchIdEntity;
410
- } & RelationOptionsBase<fromEntity, toEntity, optionsType>;
411
- export type RelationOptionsBase<fromEntity, toEntity, optionsType extends LoadOptions<toEntity> = LoadOptions<toEntity>> = {
511
+ /**
512
+ * Find options to apply to the relation when fetching related entities.
513
+ * You can specify a predefined set of find options or provide a function that takes the source entity
514
+ * and returns find options dynamically.
515
+ * These options allow you to customize how related entities are retrieved.
516
+ */
412
517
  findOptions?: optionsType | ((entity: fromEntity) => optionsType);
518
+ /**
519
+ * Determines whether the relation should be included by default when querying the source entity.
520
+ * When set to true, related entities will be automatically included when querying the source entity.
521
+ * If false or not specified, related entities will need to be explicitly included using the `include` option.
522
+ */
413
523
  defaultIncluded?: boolean;
414
- } & FieldOptions<fromEntity, toEntity>;
524
+ } & Pick<FieldOptions, 'caption'>;
415
525
  export type ObjectMembersOnly<T> = {
416
526
  [K in keyof Pick<T, {
417
527
  [K in keyof T]: T[K] extends object | undefined | null ? T[K] extends Date | undefined | null ? never : K : never;
418
528
  }[keyof T]>]: T[K];
419
529
  };
420
530
  export type MembersToInclude<T> = {
421
- [K in keyof ObjectMembersOnly<T>]?: true | (T[K] extends Array<any> ? FindOptions<T[K][number]> : FindFirstOptions<T[K]>);
531
+ [K in keyof ObjectMembersOnly<T>]?: boolean | (NonNullable<T[K]> extends Array<any> ? FindOptions<NonNullable<T[K]>[number]> : FindFirstOptions<NonNullable<T[K]>>);
422
532
  };
423
533
  export type RepositoryRelations<entityType> = {
424
- [K in keyof ObjectMembersOnly<entityType>]: entityType[K] extends Array<infer R> ? Repository<R> : entityType[K] extends infer R ? {
534
+ [K in keyof ObjectMembersOnly<entityType>]-?: NonNullable<entityType[K]> extends Array<infer R> ? Repository<R> : entityType[K] extends infer R ? {
425
535
  findOne: (options?: FindOptionsBase<R>) => Promise<R>;
426
536
  } : never;
427
537
  };
538
+ export declare type EntityIdFields<entityType> = {
539
+ [Properties in keyof Partial<OmitEB<entityType>>]?: true;
540
+ };
541
+ export interface ClassFieldDecoratorContextStub<entityType, valueType> {
542
+ readonly access: {
543
+ set(object: entityType, value: valueType): void;
544
+ };
545
+ readonly name: string;
546
+ }
547
+ export interface ClassDecoratorContextStub<Class extends new (...args: any) => any = new (...args: any) => any> {
548
+ readonly kind: 'class';
549
+ readonly name: string | undefined;
550
+ addInitializer(initializer: (this: Class) => void): void;
551
+ }
552
+ export type ClassFieldDecorator<entityType, valueType> = (target: any, context: string | ClassFieldDecoratorContextStub<entityType, valueType | undefined>, c?: any) => void;
@@ -1,2 +1,32 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ //p1 - include relations in the api docs
4
+ //p1 - include Relation options in the api docs
5
+ //p1 - fix { allowApiRead: r => r.user.name === 'superman' } } in allowed for instace docs
6
+ //p1 - fix seeallowed in ref_entity
7
+ //p1 - write doc about controlling updates of rows...
8
+ //p1 - 'eventId' autocomplete in task app did not work
9
+ //p1 - need a way to extract the fields from the relation - for generating relation based sql
10
+ //p1 - remult object was used outside context
11
+ // ```
12
+ // sqlExpression: async (e) => {
13
+ // const v = await dbNamesOf(volunteerInTask)
14
+ // return `select true from ${v} where ${
15
+ // v.task
16
+ // }=${await e.getDbName()}.${await e.fields.id.getDbName()} and ${SqlDatabase.filterToRaw<volunteerInTask>(
17
+ // repo(volunteerInTask),
18
+ // {
19
+ // canceled: false,
20
+ // }
21
+ // )}`
22
+ // },
23
+ // })
24
+ // ```
25
+ //p2 - consider includeInApi as AllowedForInstance
26
+ //p1 - why didn't this._.relations.statusChanges.insert({})work?
27
+ //p1 - active record with include thinks that the row was change!
28
+ //p1 - add docs for apply changes
29
+ //p1 - update related field with null should respect it's allowed null - otherwise we get a null error for that field.
30
+ //p1 - when the include doesn't find the many to one - it deletes the id!!!
31
+ //y1 - discuss a default date formatter
32
+ //p1 - consider using this in saving etc...
@@ -0,0 +1,14 @@
1
+ import type { EntityDataProviderFindOptions } from '../data-interfaces';
2
+ import type { Filter } from '../filter/filter-interfaces';
3
+ import type { EntityFilter, EntityOrderBy, FindOptions, LoadOptions, Repository } from './remult3';
4
+ export interface RepositoryInternal<entityType> {
5
+ createAfterFilter(orderBy: EntityOrderBy<entityType>, lastRow: entityType): Promise<EntityFilter<entityType>>;
6
+ fromJsonArray(jsonItems: any[], loadOptions: LoadOptions<entityType>): Promise<entityType[]>;
7
+ buildEntityDataProviderFindOptions(options: FindOptions<entityType>): Promise<EntityDataProviderFindOptions>;
8
+ translateWhereToFilter(where: EntityFilter<entityType>): Promise<Filter>;
9
+ getCachedById(id: any, doNotLoadIfNotFound: boolean): entityType;
10
+ getCachedByIdAsync(id: any, doNotLoadIfNotFound: boolean): Promise<entityType>;
11
+ addToCache(item: entityType): any;
12
+ }
13
+ export declare function getRepositoryInternals<entityType>(repo: Repository<entityType>): RepositoryInternal<entityType>;
14
+ export declare const getInternalKey = "getInternal";
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getInternalKey = exports.getRepositoryInternals = void 0;
4
+ function getRepositoryInternals(repo) {
5
+ var x = repo;
6
+ if (typeof x[exports.getInternalKey] === 'function')
7
+ return x[exports.getInternalKey]();
8
+ throw Error('Error getting repository internal from ' + repo);
9
+ }
10
+ exports.getRepositoryInternals = getRepositoryInternals;
11
+ exports.getInternalKey = 'getInternal';
@@ -440,7 +440,7 @@ function BackendMethod(options) {
440
440
  http])];
441
441
  case 4:
442
442
  r = _h.sent();
443
- return [4 /*yield*/, defs._updateEntityBasedOnApi(r.rowInfo.data)];
443
+ return [4 /*yield*/, defs._updateEntityBasedOnApi(r.rowInfo.data, true)];
444
444
  case 5:
445
445
  _h.sent();
446
446
  return [2 /*return*/, r.result];
package/src/sort.d.ts CHANGED
@@ -6,9 +6,9 @@ export declare class Sort {
6
6
  Segments: SortSegment[];
7
7
  reverse(): Sort;
8
8
  compare(a: any, b: any, getFieldKey?: (field: FieldMetadata) => string): number;
9
- static translateOrderByToSort<T>(entityDefs: EntityMetadata<T>, orderBy: EntityOrderBy<T>): Sort;
10
- static createUniqueSort<T>(entityMetadata: EntityMetadata<T>, orderBy: Sort): Sort;
11
- static createUniqueEntityOrderBy<T>(entityMetadata: EntityMetadata<T>, orderBy: EntityOrderBy<T>): EntityOrderBy<T>;
9
+ static translateOrderByToSort<T>(entityDefs: EntityMetadata<T>, orderBy?: EntityOrderBy<T>): Sort;
10
+ static createUniqueSort<T>(entityMetadata: EntityMetadata<T>, orderBy?: Sort): Sort;
11
+ static createUniqueEntityOrderBy<T>(entityMetadata: EntityMetadata<T>, orderBy?: EntityOrderBy<T>): EntityOrderBy<T>;
12
12
  }
13
13
  export interface SortSegment {
14
14
  field: FieldMetadata;
package/src/sort.js CHANGED
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Sort = void 0;
4
4
  var tslib_1 = require("tslib");
5
+ var internals_1 = require("../internals");
5
6
  var CompoundIdField_1 = require("./CompoundIdField");
6
7
  var Sort = /** @class */ (function () {
7
8
  function Sort() {
@@ -57,8 +58,8 @@ var Sort = /** @class */ (function () {
57
58
  var r = 0;
58
59
  for (var i = 0; i < this.Segments.length; i++) {
59
60
  var seg = this.Segments[i];
60
- var left = a[getFieldKey(seg.field)];
61
- var right = b[getFieldKey(seg.field)];
61
+ var left = fixValueForSort(a[getFieldKey(seg.field)]);
62
+ var right = fixValueForSort(b[getFieldKey(seg.field)]);
62
63
  if (left > right)
63
64
  r = 1;
64
65
  else if (left < right)
@@ -74,35 +75,59 @@ var Sort = /** @class */ (function () {
74
75
  Sort.translateOrderByToSort = function (entityDefs, orderBy) {
75
76
  if (!orderBy)
76
77
  return undefined;
77
- var sort;
78
+ var sort = new Sort();
78
79
  if (orderBy) {
79
- sort = new Sort();
80
- for (var key in orderBy) {
80
+ var _loop_1 = function (key) {
81
81
  if (Object.prototype.hasOwnProperty.call(orderBy, key)) {
82
- var element = orderBy[key];
82
+ var element_1 = orderBy[key];
83
83
  var field = entityDefs.fields.find(key);
84
- if (field) {
85
- switch (element) {
84
+ var addSegment = function (field) {
85
+ switch (element_1) {
86
86
  case 'desc':
87
87
  sort.Segments.push({ field: field, isDescending: true });
88
88
  break;
89
89
  case 'asc':
90
90
  sort.Segments.push({ field: field });
91
91
  }
92
+ };
93
+ if (field) {
94
+ var rel = (0, internals_1.getRelationInfo)(field.options);
95
+ var op = field.options;
96
+ if ((rel === null || rel === void 0 ? void 0 : rel.type) === 'toOne') {
97
+ if (typeof op.field === 'string') {
98
+ addSegment(entityDefs.fields.find(op.field));
99
+ }
100
+ else {
101
+ if (op.fields) {
102
+ for (var key_1 in op.fields) {
103
+ if (Object.prototype.hasOwnProperty.call(op.fields, key_1)) {
104
+ var keyInMyEntity = op.fields[key_1];
105
+ addSegment(entityDefs.fields.find(keyInMyEntity.toString()));
106
+ }
107
+ }
108
+ }
109
+ }
110
+ }
111
+ else
112
+ addSegment(field);
92
113
  }
93
114
  }
115
+ };
116
+ for (var key in orderBy) {
117
+ _loop_1(key);
94
118
  }
95
119
  }
96
120
  return sort;
97
121
  };
98
122
  Sort.createUniqueSort = function (entityMetadata, orderBy) {
99
123
  var e_3, _a;
100
- if (!orderBy || Object.keys(orderBy).length === 0)
124
+ if ((!orderBy || Object.keys(orderBy).length === 0) &&
125
+ entityMetadata.options.defaultOrderBy)
101
126
  orderBy = Sort.translateOrderByToSort(entityMetadata, entityMetadata.options.defaultOrderBy);
102
127
  if (!orderBy)
103
128
  orderBy = new Sort({ field: entityMetadata.idMetadata.field });
104
129
  if (entityMetadata.idMetadata.field instanceof CompoundIdField_1.CompoundIdField) {
105
- var _loop_1 = function (field) {
130
+ var _loop_2 = function (field) {
106
131
  if (!orderBy.Segments.find(function (x) { return x.field == field; })) {
107
132
  orderBy.Segments.push({ field: field });
108
133
  }
@@ -110,7 +135,7 @@ var Sort = /** @class */ (function () {
110
135
  try {
111
136
  for (var _b = tslib_1.__values(entityMetadata.idMetadata.field.fields), _c = _b.next(); !_c.done; _c = _b.next()) {
112
137
  var field = _c.value;
113
- _loop_1(field);
138
+ _loop_2(field);
114
139
  }
115
140
  }
116
141
  catch (e_3_1) { e_3 = { error: e_3_1 }; }
@@ -161,3 +186,10 @@ var Sort = /** @class */ (function () {
161
186
  return Sort;
162
187
  }());
163
188
  exports.Sort = Sort;
189
+ function fixValueForSort(a) {
190
+ if (a == undefined || a == null)
191
+ return a;
192
+ if (a.id !== undefined)
193
+ return a.id;
194
+ return a;
195
+ }