remult 0.16.5 → 0.17.0-exp.2

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 (74) hide show
  1. package/README.md +5 -27
  2. package/esm/index.d.ts +2 -1
  3. package/esm/remult-express.d.ts +32 -0
  4. package/esm/remult-express.js +130 -2
  5. package/esm/remult-fastify.js +0 -2
  6. package/esm/remult-knex/index.js +2 -9
  7. package/esm/server/expressBridge.d.ts +44 -10
  8. package/esm/server/expressBridge.js +27 -20
  9. package/esm/src/backend-tests/backend-database-test-setup.backend-spec.d.ts +0 -1
  10. package/esm/src/backend-tests/backend-database-test-setup.backend-spec.js +0 -10
  11. package/esm/src/backend-tests/my-test.backend-spec.js +0 -48
  12. package/esm/src/column.d.ts +3 -3
  13. package/esm/src/context.d.ts +2 -0
  14. package/esm/src/context.js +11 -0
  15. package/esm/src/data-api.d.ts +6 -2
  16. package/esm/src/data-api.js +17 -4
  17. package/esm/src/data-providers/array-entity-data-provider.js +1 -16
  18. package/esm/src/data-providers/rest-data-provider.d.ts +4 -0
  19. package/esm/src/data-providers/rest-data-provider.js +11 -7
  20. package/esm/src/live-query/LiveQuery.js +7 -5
  21. package/esm/src/live-query/LiveQueryManager.d.ts +1 -2
  22. package/esm/src/live-query/LiveQueryManager.js +18 -16
  23. package/esm/src/remult-proxy.d.ts +1 -1
  24. package/esm/src/remult-proxy.js +11 -9
  25. package/esm/src/remult3/RepositoryImplementation.d.ts +6 -3
  26. package/esm/src/remult3/RepositoryImplementation.js +39 -22
  27. package/esm/src/remult3/getId.d.ts +2 -0
  28. package/esm/src/remult3/getId.js +7 -0
  29. package/esm/src/remult3/remult3.d.ts +10 -6
  30. package/esm/src/server-action.js +4 -3
  31. package/esm/src/shared-tests/db-tests-setup.d.ts +1 -1
  32. package/esm/src/shared-tests/db-tests-setup.js +0 -1
  33. package/esm/src/sort.d.ts +1 -0
  34. package/esm/src/sort.js +18 -0
  35. package/esm/src/tests/testHelper.spec.d.ts +2 -0
  36. package/esm/src/tests/testHelper.spec.js +60 -57
  37. package/esm/src/valueConverters.js +0 -2
  38. package/index.d.ts +2 -1
  39. package/package.json +1 -1
  40. package/remult-express.d.ts +32 -0
  41. package/remult-express.js +193 -3
  42. package/remult-fastify.js +0 -2
  43. package/remult-knex/index.js +8 -16
  44. package/server/expressBridge.d.ts +44 -10
  45. package/server/expressBridge.js +37 -20
  46. package/src/backend-tests/backend-database-test-setup.backend-spec.d.ts +0 -1
  47. package/src/backend-tests/backend-database-test-setup.backend-spec.js +1 -11
  48. package/src/backend-tests/my-test.backend-spec.js +0 -57
  49. package/src/column.d.ts +3 -3
  50. package/src/context.d.ts +2 -0
  51. package/src/context.js +11 -0
  52. package/src/data-api.d.ts +6 -2
  53. package/src/data-api.js +23 -15
  54. package/src/data-providers/array-entity-data-provider.js +1 -16
  55. package/src/data-providers/rest-data-provider.d.ts +4 -0
  56. package/src/data-providers/rest-data-provider.js +11 -7
  57. package/src/live-query/LiveQuery.js +6 -4
  58. package/src/live-query/LiveQueryManager.d.ts +1 -2
  59. package/src/live-query/LiveQueryManager.js +64 -62
  60. package/src/remult-proxy.d.ts +1 -1
  61. package/src/remult-proxy.js +19 -9
  62. package/src/remult3/RepositoryImplementation.d.ts +6 -3
  63. package/src/remult3/RepositoryImplementation.js +69 -42
  64. package/src/remult3/getId.d.ts +2 -0
  65. package/src/remult3/getId.js +11 -0
  66. package/src/remult3/remult3.d.ts +10 -6
  67. package/src/server-action.js +3 -2
  68. package/src/shared-tests/db-tests-setup.d.ts +1 -1
  69. package/src/shared-tests/db-tests-setup.js +0 -1
  70. package/src/sort.d.ts +1 -0
  71. package/src/sort.js +18 -0
  72. package/src/tests/testHelper.spec.d.ts +2 -0
  73. package/src/tests/testHelper.spec.js +99 -95
  74. package/src/valueConverters.js +0 -2
@@ -1,9 +1,10 @@
1
1
  import { customUrlToken, buildFilterFromRequestParameters } from './filter/filter-interfaces';
2
2
  import { Filter } from './filter/filter-interfaces';
3
3
  export class DataApi {
4
- constructor(repository, remult) {
4
+ constructor(repository, remult, liveQueryProvider) {
5
5
  this.repository = repository;
6
6
  this.remult = remult;
7
+ this.liveQueryProvider = liveQueryProvider;
7
8
  }
8
9
  httpGet(res, req) {
9
10
  if (req.get("__action") == "count") {
@@ -13,7 +14,10 @@ export class DataApi {
13
14
  return this.getArray(res, req);
14
15
  }
15
16
  httpPost(res, req, body) {
16
- switch (req.get("__action")) {
17
+ const action = req?.get("__action");
18
+ if (action?.startsWith("subscribe"))
19
+ return this.getArray(res, req, body);
20
+ switch (action) {
17
21
  case "get":
18
22
  return this.getArray(res, req, body);
19
23
  case "count":
@@ -89,10 +93,19 @@ export class DataApi {
89
93
  findOptions.limit = limit;
90
94
  findOptions.page = +request.get("_page");
91
95
  }
92
- await this.repository.find(findOptions)
96
+ const action = request?.get("__action");
97
+ const r = await this.repository.find(findOptions)
93
98
  .then(async (r) => {
94
- response.success(await Promise.all(r.map(async (y) => this.repository.getEntityRef(y).toApiJson())));
99
+ return await Promise.all(r.map(async (y) => this.repository.getEntityRef(y).toApiJson()));
95
100
  });
101
+ if (this.liveQueryProvider && action?.startsWith("subscribe")) {
102
+ response.success({
103
+ id: this.liveQueryProvider.subscribe(this.repository, action.split('|')[1], findOptions, this.remult, r.map(y => this.repository.getEntityRef(y).getId())),
104
+ result: r
105
+ });
106
+ return;
107
+ }
108
+ response.success(r);
96
109
  }
97
110
  catch (err) {
98
111
  response.error(err);
@@ -66,22 +66,7 @@ export class ArrayEntityDataProvider {
66
66
  }
67
67
  if (options.orderBy) {
68
68
  rows = rows.sort((a, b) => {
69
- let r = 0;
70
- for (let i = 0; i < options.orderBy.Segments.length; i++) {
71
- let seg = options.orderBy.Segments[i];
72
- let left = a[seg.field.key];
73
- let right = b[seg.field.key];
74
- if (left > right)
75
- r = 1;
76
- else if (left < right)
77
- r = -1;
78
- if (r != 0) {
79
- if (seg.isDescending)
80
- r *= -1;
81
- return r;
82
- }
83
- }
84
- return r;
69
+ return options.orderBy.compare(a, b);
85
70
  });
86
71
  }
87
72
  rows = pageArray(rows, options);
@@ -19,6 +19,10 @@ export declare class RestEntityDataProvider implements EntityDataProvider {
19
19
  translateToJson(row: any): {};
20
20
  count(where: Filter): Promise<number>;
21
21
  find(options: EntityDataProviderFindOptions): Promise<Array<any>>;
22
+ buildFindRequest(options: EntityDataProviderFindOptions): {
23
+ filterObject: any;
24
+ url: UrlBuilder;
25
+ };
22
26
  update(id: any, data: any): Promise<any>;
23
27
  delete(id: any): Promise<void>;
24
28
  insert(data: any): Promise<any>;
@@ -55,6 +55,16 @@ export class RestEntityDataProvider {
55
55
  return this.http().get(url.url).then(r => +(r.count));
56
56
  }
57
57
  find(options) {
58
+ let { filterObject, url } = this.buildFindRequest(options);
59
+ if (filterObject) {
60
+ url.add("__action", "get");
61
+ return this.http().post(url.url, filterObject).then(x => x.map(y => this.translateFromJson(y)));
62
+ }
63
+ else
64
+ return this.http().get(url.url).then(x => x.map(y => this.translateFromJson(y)));
65
+ ;
66
+ }
67
+ buildFindRequest(options) {
58
68
  let url = new UrlBuilder(this.url());
59
69
  let filterObject;
60
70
  if (options) {
@@ -82,13 +92,7 @@ export class RestEntityDataProvider {
82
92
  if (options.page)
83
93
  url.add('_page', options.page);
84
94
  }
85
- if (filterObject) {
86
- url.add("__action", "get");
87
- return this.http().post(url.url, filterObject).then(x => x.map(y => this.translateFromJson(y)));
88
- }
89
- else
90
- return this.http().get(url.url).then(x => x.map(y => this.translateFromJson(y)));
91
- ;
95
+ return { filterObject, url };
92
96
  }
93
97
  update(id, data) {
94
98
  let result = {};
@@ -1,13 +1,14 @@
1
- import { getEntityRef, remult as defaultRemult, Sort } from '../../index';
1
+ import { remult as defaultRemult, Sort } from '../../index';
2
2
  import { v4 as uuid } from 'uuid';
3
3
  import { RestEntityDataProvider } from '../data-providers/rest-data-provider';
4
4
  import { buildRestDataProvider } from '../context';
5
+ import { getId } from '../remult3/getId';
5
6
  export const streamUrl = 'stream1';
6
7
  class LiveQueryOnFrontEnd {
7
8
  constructor(repo, query) {
8
9
  this.repo = repo;
9
10
  this.query = query;
10
- this.items = [];
11
+ this.defaultQueryState = [];
11
12
  this.listeners = [];
12
13
  }
13
14
  async setAllItems(result) {
@@ -19,6 +20,7 @@ class LiveQueryOnFrontEnd {
19
20
  });
20
21
  }
21
22
  forListeners(what) {
23
+ // what(x => this.defaultQueryState = x(this.defaultQueryState));
22
24
  for (const l of this.listeners) {
23
25
  what(l);
24
26
  }
@@ -41,7 +43,7 @@ class LiveQueryOnFrontEnd {
41
43
  listener(items => {
42
44
  if (!items)
43
45
  items = [];
44
- return sort(items.map(x => this.repo.getEntityRef(x).getId() === message.data.oldId ? item : x));
46
+ return sort(items.map(x => getId(this.repo.metadata, x) === message.data.oldId ? item : x));
45
47
  });
46
48
  });
47
49
  break;
@@ -61,7 +63,7 @@ class LiveQueryOnFrontEnd {
61
63
  this.forListeners(listener => listener(items => {
62
64
  if (!items)
63
65
  items = [];
64
- return this.items.filter(x => getEntityRef(x).getId() !== message.data.id);
66
+ return items.filter(x => getId(this.repo.metadata, x) !== message.data.id);
65
67
  }));
66
68
  break;
67
69
  }
@@ -152,7 +154,7 @@ export class LiveQueryClient {
152
154
  this.runPromise(this.provider.get(url.url).then(thenResult));
153
155
  }
154
156
  else {
155
- onResult(x => q.items);
157
+ onResult(x => [...q.defaultQueryState]);
156
158
  }
157
159
  q.listeners.push(onResult);
158
160
  onUnsubscribe = () => {
@@ -2,12 +2,11 @@ import { Remult } from '../..';
2
2
  import { Repository, EntityRef, FindOptions } from '../remult3';
3
3
  import { LiveQueryProvider } from '../data-api';
4
4
  import { liveQueryMessage } from './LiveQuery';
5
- export declare class LiveQueryManager implements LiveQueryProvider {
5
+ export declare class LiveQueryPublisher implements LiveQueryProvider {
6
6
  private dispatcher;
7
7
  constructor(dispatcher: ServerEventDispatcher);
8
8
  subscribe(repo: Repository<any>, clientId: string, findOptions: FindOptions<any>, remult: Remult, ids: any[]): string;
9
9
  clients: clientInfo[];
10
- sendMessage(key: string, message: liveQueryMessage): void;
11
10
  hasListeners(ref: EntityRef<any>): boolean;
12
11
  runPromise(p: Promise<any>): void;
13
12
  saved(ref: EntityRef<any>): void;
@@ -1,5 +1,5 @@
1
1
  import { v4 as uuid } from 'uuid';
2
- export class LiveQueryManager {
2
+ export class LiveQueryPublisher {
3
3
  constructor(dispatcher) {
4
4
  this.dispatcher = dispatcher;
5
5
  this.clients = [];
@@ -19,15 +19,6 @@ export class LiveQueryManager {
19
19
  });
20
20
  return id;
21
21
  }
22
- sendMessage(key, message) {
23
- for (const c of this.clients) {
24
- for (const q of c.queries) {
25
- if (q.repo.metadata.key === key) {
26
- this.dispatcher.sendQueryMessage({ clientId: c.clientId, queryId: q.id, message });
27
- }
28
- }
29
- }
30
- }
31
22
  hasListeners(ref) {
32
23
  for (const c of this.clients) {
33
24
  for (const q of c.queries) {
@@ -87,11 +78,22 @@ export class LiveQueryManager {
87
78
  }
88
79
  }
89
80
  deleted(ref) {
90
- if (!this.hasListeners(ref))
91
- return;
92
- this.sendMessage(ref.metadata.key, {
93
- type: "remove",
94
- data: { id: ref.getId() }
95
- });
81
+ const id = ref.getOriginalId();
82
+ for (const c of this.clients) {
83
+ for (const q of c.queries) {
84
+ if (q.repo.metadata.key === ref.metadata.key) {
85
+ if (q.ids.includes(id)) {
86
+ this.dispatcher.sendQueryMessage({
87
+ clientId: c.clientId, queryId: q.id, message: {
88
+ type: "remove",
89
+ data: {
90
+ id: id
91
+ }
92
+ }
93
+ });
94
+ }
95
+ }
96
+ }
97
+ }
96
98
  }
97
99
  }
@@ -1,2 +1,2 @@
1
- import { Remult } from "./context";
1
+ import type { Remult } from "./context";
2
2
  export declare const remult: Remult;
@@ -1,13 +1,20 @@
1
- import { Remult } from "./context";
2
- import { RepositoryImplementation } from "./remult3";
3
- let defaultRemult = new Remult();
4
1
  /*@internal*/
5
2
  export class RemultProxy {
6
3
  constructor() {
7
4
  /*@internal*/
8
- this.remultFactory = () => defaultRemult;
5
+ this.remultFactory = () => RemultProxy.defaultRemult;
9
6
  this.repo = (...args) => this.remultFactory().repo(...args);
10
7
  }
8
+ get liveQueryProvider() { return this.remultFactory().liveQueryProvider; }
9
+ ;
10
+ set liveQueryProvider(val) { this.remultFactory().liveQueryProvider = val; }
11
+ ;
12
+ get _changeListener() {
13
+ return this.remultFactory()._changeListener;
14
+ }
15
+ set _changeListener(val) {
16
+ this.remultFactory()._changeListener = val;
17
+ }
11
18
  call(backendMethod, self, ...args) {
12
19
  return this.remultFactory().call(backendMethod, self, ...args);
13
20
  }
@@ -31,10 +38,6 @@ export class RemultProxy {
31
38
  clearAllCache() {
32
39
  return this.remultFactory().clearAllCache();
33
40
  }
34
- /*@internal*/
35
- resetFactory() {
36
- this.remultFactory = () => defaultRemult;
37
- }
38
41
  get user() {
39
42
  return this.remultFactory().user;
40
43
  }
@@ -49,4 +52,3 @@ export class RemultProxy {
49
52
  }
50
53
  }
51
54
  export const remult = new RemultProxy();
52
- RepositoryImplementation.defaultRemult = remult;
@@ -5,13 +5,12 @@ import { EntityMetadata, FieldRef, FieldsRef, EntityFilter, FindOptions, Reposit
5
5
  import { ClassType } from "../../classType";
6
6
  import { Remult, Unobserve } from "../context";
7
7
  import { entityEventListener } from "../__EntityValueProvider";
8
- import { DataProvider, EntityDataProvider } from "../data-interfaces";
8
+ import { DataProvider, EntityDataProvider, EntityDataProviderFindOptions } from "../data-interfaces";
9
9
  import { RefSubscriber } from ".";
10
10
  export declare class RepositoryImplementation<entityType> implements Repository<entityType> {
11
11
  private entity;
12
- private remult;
12
+ remult: Remult;
13
13
  private dataProvider;
14
- static defaultRemult: Remult;
15
14
  createAfterFilter(orderBy: EntityOrderBy<entityType>, lastRow: entityType): Promise<EntityFilter<entityType>>;
16
15
  private _info;
17
16
  private __edp;
@@ -43,6 +42,7 @@ export declare class RepositoryImplementation<entityType> implements Repository<
43
42
  save(item: Partial<OmitEB<entityType>>[]): Promise<entityType[]>;
44
43
  save(item: Partial<OmitEB<entityType>>): Promise<entityType>;
45
44
  find(options: FindOptions<entityType>): Promise<entityType[]>;
45
+ buildEntityDataProviderFindOptions(options: FindOptions<entityType>): Promise<EntityDataProviderFindOptions>;
46
46
  private mapRawDataToResult;
47
47
  count(where?: EntityFilter<entityType>): Promise<number>;
48
48
  private cache;
@@ -89,6 +89,7 @@ declare abstract class rowHelperBase<T> {
89
89
  copyDataToObject(): any;
90
90
  originalValues: any;
91
91
  saveOriginalData(): void;
92
+ saveMoreOriginalData(): void;
92
93
  validate(): Promise<boolean>;
93
94
  __validateEntity(): Promise<void>;
94
95
  __performColumnAndEntityValidations(): Promise<void>;
@@ -106,6 +107,7 @@ export declare class rowHelperImplementation<T> extends rowHelperBase<T> impleme
106
107
  get apiInsertAllowed(): boolean;
107
108
  metadata: EntityMetadata<T>;
108
109
  getId(): any;
110
+ saveMoreOriginalData(): void;
109
111
  private _wasDeleted;
110
112
  wasDeleted(): boolean;
111
113
  undoChanges(): void;
@@ -118,6 +120,7 @@ export declare class rowHelperImplementation<T> extends rowHelperBase<T> impleme
118
120
  delete(): Promise<void>;
119
121
  loadDataFrom(data: any, loadItems?: FieldMetadata[]): Promise<void>;
120
122
  id: any;
123
+ originalId: any;
121
124
  getOriginalId(): any;
122
125
  private calcServerExpression;
123
126
  isNew(): boolean;
@@ -6,6 +6,8 @@ import { v4 as uuid } from 'uuid';
6
6
  import { ValueConverters } from "../valueConverters";
7
7
  import { filterHelper } from "../filter/filter-interfaces";
8
8
  import { assign } from "../../assign";
9
+ import { remult as defaultRemult } from "../remult-proxy";
10
+ import { getId } from "./getId";
9
11
  //import { remult } from "../remult-proxy";
10
12
  let classValidatorValidate = undefined;
11
13
  // import("class-validator".toString())
@@ -165,8 +167,10 @@ export class RepositoryImplementation {
165
167
  instance[field.key] = entity[field.key];
166
168
  }
167
169
  let row = new rowHelperImplementation(this._info, instance, this, this.edp, this.remult, false);
168
- if (id)
170
+ if (id) {
169
171
  row.id = id;
172
+ row.originalId = id;
173
+ }
170
174
  else
171
175
  row.id = row.getId();
172
176
  ref = row;
@@ -197,17 +201,9 @@ export class RepositoryImplementation {
197
201
  }
198
202
  async find(options) {
199
203
  Remult.onFind(this._info, options);
200
- let opt = {};
201
204
  if (!options)
202
205
  options = {};
203
- opt = {};
204
- if (!options.orderBy || Object.keys(options.orderBy).length === 0) {
205
- options.orderBy = this._info.entityInfo.defaultOrderBy;
206
- }
207
- opt.where = await this.translateWhereToFilter(options.where);
208
- opt.orderBy = Sort.translateOrderByToSort(this.metadata, options.orderBy);
209
- opt.limit = options.limit;
210
- opt.page = options.page;
206
+ let opt = await this.buildEntityDataProviderFindOptions(options);
211
207
  let rawRows = await this.edp.find(opt);
212
208
  let loadFields = undefined;
213
209
  if (options.load)
@@ -242,6 +238,18 @@ export class RepositoryImplementation {
242
238
  }
243
239
  }
244
240
  }
241
+ async buildEntityDataProviderFindOptions(options) {
242
+ let opt = {};
243
+ opt = {};
244
+ if (!options.orderBy || Object.keys(options.orderBy).length === 0) {
245
+ options.orderBy = this._info.entityInfo.defaultOrderBy;
246
+ }
247
+ opt.where = await this.translateWhereToFilter(options.where);
248
+ opt.orderBy = Sort.translateOrderByToSort(this.metadata, options.orderBy);
249
+ opt.limit = options.limit;
250
+ opt.page = options.page;
251
+ return opt;
252
+ }
245
253
  async mapRawDataToResult(r, loadFields) {
246
254
  if (!r)
247
255
  return undefined;
@@ -622,6 +630,9 @@ class rowHelperBase {
622
630
  }
623
631
  saveOriginalData() {
624
632
  this.originalValues = this.copyDataToObject();
633
+ this.saveMoreOriginalData();
634
+ }
635
+ saveMoreOriginalData() {
625
636
  }
626
637
  async validate() {
627
638
  this.__clearErrorsAndReportChanged();
@@ -711,10 +722,10 @@ export class rowHelperImplementation extends rowHelperBase {
711
722
  get apiDeleteAllowed() { return this.remult.isAllowedForInstance(this.instance, this.metadata.options.allowApiDelete); }
712
723
  get apiInsertAllowed() { return this.remult.isAllowedForInstance(this.instance, this.metadata.options.allowApiInsert); }
713
724
  getId() {
714
- if (this.info.idMetadata.field instanceof CompoundIdField)
715
- return this.info.idMetadata.field.getId(this.instance);
716
- else
717
- return this.instance[this.info.idMetadata.field.key];
725
+ return getId(this.info, this.instance);
726
+ }
727
+ saveMoreOriginalData() {
728
+ this.originalId = this.getId();
718
729
  }
719
730
  wasDeleted() {
720
731
  this._subscribers?.reportObserved();
@@ -805,6 +816,7 @@ export class rowHelperImplementation extends rowHelperBase {
805
816
  }
806
817
  }
807
818
  await this.loadDataFrom(updatedRow);
819
+ this.repository.remult._changeListener.saved(this);
808
820
  if (this.info.entityInfo.saved)
809
821
  await this.info.entityInfo.saved(this.instance);
810
822
  this.saveOriginalData();
@@ -831,6 +843,7 @@ export class rowHelperImplementation extends rowHelperBase {
831
843
  this.__assertValidity();
832
844
  try {
833
845
  await this.edp.delete(this.id);
846
+ this.repository.remult._changeListener.deleted(this);
834
847
  if (this.info.entityInfo.deleted)
835
848
  await this.info.entityInfo.deleted(this.instance);
836
849
  if (this.repository.listeners)
@@ -861,14 +874,10 @@ export class rowHelperImplementation extends rowHelperBase {
861
874
  this.instance[col.key] = data[col.key];
862
875
  }
863
876
  await this.calcServerExpression();
864
- if (this.repository.metadata.idMetadata.field instanceof CompoundIdField) {
865
- this.id = this.repository.metadata.idMetadata.field.getId(this.instance);
866
- }
867
- else
868
- this.id = data[this.repository.metadata.idMetadata.field.key];
877
+ this.id = getId(this.info, this.instance);
869
878
  }
870
879
  getOriginalId() {
871
- return this.id;
880
+ return this.originalId;
872
881
  }
873
882
  async calcServerExpression() {
874
883
  if (isBackend())
@@ -913,7 +922,7 @@ export function getFields(container, remult) {
913
922
  return getControllerRef(container, remult).fields;
914
923
  }
915
924
  export function getControllerRef(container, remultArg) {
916
- const remultVar = remultArg || RepositoryImplementation.defaultRemult;
925
+ const remultVar = remultArg || defaultRemult;
917
926
  let result = container[controllerColumns];
918
927
  if (!result)
919
928
  result = container[entityMember];
@@ -1658,7 +1667,7 @@ export class EntityBase {
1658
1667
  }
1659
1668
  export class ControllerBase {
1660
1669
  constructor(remult) {
1661
- this.remult = remult || RepositoryImplementation.defaultRemult;
1670
+ this.remult = remult || defaultRemult;
1662
1671
  }
1663
1672
  assign(values) {
1664
1673
  assign(this, values);
@@ -1678,6 +1687,14 @@ class QueryResultImpl {
1678
1687
  this.options.pageSize = queryConfig.defaultPageSize;
1679
1688
  }
1680
1689
  }
1690
+ subscribe(onResult) {
1691
+ return this.repo.remult.liveQueryProvider.subscribe(this.repo, {
1692
+ limit: this.options.pageSize,
1693
+ load: this.options.load,
1694
+ orderBy: this.options.orderBy,
1695
+ where: this.options.where
1696
+ }, onResult);
1697
+ }
1681
1698
  async getPage(page) {
1682
1699
  if (page < 1)
1683
1700
  page = 1;
@@ -0,0 +1,2 @@
1
+ import type { EntityMetadata } from "./remult3";
2
+ export declare function getId<entityType>(meta: EntityMetadata<entityType>, instance: entityType): any;
@@ -0,0 +1,7 @@
1
+ import { CompoundIdField } from '../column';
2
+ export function getId(meta, instance) {
3
+ if (meta.idMetadata.field instanceof CompoundIdField)
4
+ return meta.idMetadata.field.getId(instance);
5
+ else
6
+ return instance[meta.idMetadata.field.key];
7
+ }
@@ -15,7 +15,8 @@ export interface EntityRef<entityType> extends Subscribable {
15
15
  wasDeleted(): boolean;
16
16
  fields: FieldsRef<entityType>;
17
17
  error: string;
18
- getId(): any;
18
+ getId(): idType<entityType>;
19
+ getOriginalId(): idType<entityType>;
19
20
  repository: Repository<entityType>;
20
21
  metadata: EntityMetadata<entityType>;
21
22
  toApiJson(): any;
@@ -108,6 +109,11 @@ export interface EntityMetadata<entityType = any> {
108
109
  getDbName(): Promise<string>;
109
110
  }
110
111
  export declare type OmitEB<T> = Omit<T, keyof import('./RepositoryImplementation').EntityBase>;
112
+ export declare type idType<entityType> = entityType extends {
113
+ id?: number;
114
+ } ? number : entityType extends {
115
+ id?: string;
116
+ } ? string : (string | number);
111
117
  /**used to perform CRUD operations on an `entityType` */
112
118
  export interface Repository<entityType> {
113
119
  /** returns a result array based on the provided options */
@@ -120,11 +126,7 @@ export interface Repository<entityType> {
120
126
  * */
121
127
  findFirst(where?: EntityFilter<entityType>, options?: FindFirstOptions<entityType>): Promise<entityType>;
122
128
  /** returns the items that matches the idm the result is cached unless specified differently in the `options` parameter */
123
- findId(id: entityType extends {
124
- id?: number;
125
- } ? number : entityType extends {
126
- id?: string;
127
- } ? string : (string | number), options?: FindFirstOptionsBase<entityType>): Promise<entityType>;
129
+ findId(id: idType<entityType>, options?: FindFirstOptionsBase<entityType>): Promise<entityType>;
128
130
  /** An alternative form of fetching data from the API server, which is intended for operating on large numbers of entity objects.
129
131
  *
130
132
  * It also has it's own paging mechanism that can be used n paging scenarios.
@@ -298,6 +300,8 @@ export interface QueryResult<entityType> {
298
300
  getPage(pageNumber?: number): Promise<entityType[]>;
299
301
  /** Performs an operation on all the items matching the query criteria */
300
302
  forEach(what: (item: entityType) => Promise<any>): Promise<number>;
303
+ /**@Experimental */
304
+ subscribe(onResult: (reducer: (prevState: entityType[]) => entityType[]) => void): VoidFunction;
301
305
  }
302
306
  /** An interface used to paginating using the `query` method in the `Repository` object */
303
307
  export interface Paginator<entityType> {
@@ -1,7 +1,8 @@
1
1
  import 'reflect-metadata';
2
2
  import { Remult, allEntities, classHelpers, ClassHelper, setControllerSettings, buildRestDataProvider } from './context';
3
3
  import { SqlDatabase } from './data-providers/sql-database';
4
- import { getEntityRef, decorateColumnSettings, getEntitySettings, getControllerRef, RepositoryImplementation } from './remult3';
4
+ import { getEntityRef, decorateColumnSettings, getEntitySettings, getControllerRef } from './remult3';
5
+ import { remult } from './remult-proxy';
5
6
  export class Action {
6
7
  constructor(actionUrl, queue, allowed) {
7
8
  this.actionUrl = actionUrl;
@@ -10,9 +11,9 @@ export class Action {
10
11
  }
11
12
  async run(pIn, baseUrl, http) {
12
13
  if (baseUrl === undefined)
13
- baseUrl = RepositoryImplementation.defaultRemult.apiClient.url;
14
+ baseUrl = remult.apiClient.url;
14
15
  if (!http)
15
- http = buildRestDataProvider(RepositoryImplementation.defaultRemult.apiClient.httpClient);
16
+ http = buildRestDataProvider(remult.apiClient.httpClient);
16
17
  let r = await http.post(baseUrl + '/' + this.actionUrl, pIn);
17
18
  let p = r;
18
19
  if (p && p.queuedJobId) {
@@ -6,7 +6,7 @@ import { CategoriesForTesting } from "../tests/remult-3-entities";
6
6
  import { Status } from "../tests/testModel/models";
7
7
  export declare function itWithFocus(key: string, what: () => Promise<void>, focus?: boolean): void;
8
8
  export declare function testAll(key: string, what: dbTestWhatSignature, focus?: boolean): void;
9
- export declare function addDatabaseToTest(tester: dbTestMethodSignature): dbTestMethodSignature;
9
+ export declare function addDatabaseToTest(tester: dbTestMethodSignature): void;
10
10
  export declare function testInMemory(key: string, what: dbTestWhatSignature, focus?: boolean): void;
11
11
  export declare type dbTestWhatSignature = (db: {
12
12
  db: DataProvider;
@@ -22,7 +22,6 @@ export function addDatabaseToTest(tester) {
22
22
  test(tester);
23
23
  }
24
24
  databasesTesters.push(tester);
25
- return tester;
26
25
  }
27
26
  export function testInMemory(key, what, focus = false) {
28
27
  itWithFocus(key + " - in memory", async () => {
package/esm/src/sort.d.ts CHANGED
@@ -5,6 +5,7 @@ export declare class Sort {
5
5
  constructor(...segments: SortSegment[]);
6
6
  Segments: SortSegment[];
7
7
  reverse(): Sort;
8
+ compare(a: any, b: any): number;
8
9
  static translateOrderByToSort<T>(entityDefs: EntityMetadata<T>, orderBy: EntityOrderBy<T>): Sort;
9
10
  static createUniqueSort<T>(entityMetadata: EntityMetadata<T>, orderBy: Sort): Sort;
10
11
  static createUniqueEntityOrderBy<T>(entityMetadata: EntityMetadata<T>, orderBy: EntityOrderBy<T>): EntityOrderBy<T>;
package/esm/src/sort.js CHANGED
@@ -21,6 +21,24 @@ export class Sort {
21
21
  }
22
22
  return r;
23
23
  }
24
+ compare(a, b) {
25
+ let r = 0;
26
+ for (let i = 0; i < this.Segments.length; i++) {
27
+ let seg = this.Segments[i];
28
+ let left = a[seg.field.key];
29
+ let right = b[seg.field.key];
30
+ if (left > right)
31
+ r = 1;
32
+ else if (left < right)
33
+ r = -1;
34
+ if (r != 0) {
35
+ if (seg.isDescending)
36
+ r *= -1;
37
+ return r;
38
+ }
39
+ }
40
+ return r;
41
+ }
24
42
  static translateOrderByToSort(entityDefs, orderBy) {
25
43
  if (!orderBy)
26
44
  return undefined;
@@ -1,5 +1,6 @@
1
1
  import './frontend-database-tests-setup.spec';
2
2
  import { Remult } from "../context";
3
+ import { DataApi } from "../data-api";
3
4
  import { DataProvider, EntityDataProvider } from "../data-interfaces";
4
5
  import { InMemoryDataProvider } from "../data-providers/in-memory-database";
5
6
  import { EntityMetadata } from "../remult3";
@@ -32,3 +33,4 @@ export declare class MockRestDataProvider implements DataProvider {
32
33
  transaction(action: (dataProvider: DataProvider) => Promise<void>): Promise<void>;
33
34
  supportsCustomFilter: boolean;
34
35
  }
36
+ export declare function createMockHttpDataProvider(dataApi: DataApi<any>): import("c:/Repos/radweb/projects/core/src/data-interfaces").RestDataProviderHttpProvider;