remult 0.18.1-exp.2 → 0.18.1-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 (154) hide show
  1. package/README.md +28 -5
  2. package/esm/index.d.ts +4 -3
  3. package/esm/index.js +4 -2
  4. package/esm/live-query/ably.d.ts +6 -6
  5. package/esm/live-query/ably.js +5 -5
  6. package/esm/postgres/postgres-data-provider.d.ts +3 -1
  7. package/esm/postgres/postgres-data-provider.js +11 -1
  8. package/esm/postgres/schema-builder.d.ts +1 -1
  9. package/esm/postgres/schema-builder.js +43 -27
  10. package/esm/remult-express.d.ts +4 -22
  11. package/esm/remult-express.js +30 -28
  12. package/esm/remult-fastify.js +1 -1
  13. package/esm/remult-fresh.js +2 -2
  14. package/esm/remult-knex/index.d.ts +7 -31
  15. package/esm/remult-knex/index.js +71 -42
  16. package/esm/remult-mongo.d.ts +9 -2
  17. package/esm/remult-mongo.js +24 -8
  18. package/esm/remult-next.d.ts +11 -0
  19. package/esm/remult-next.js +27 -0
  20. package/esm/server/expressBridge.d.ts +20 -52
  21. package/esm/server/expressBridge.js +55 -29
  22. package/esm/server/index.d.ts +3 -1
  23. package/esm/server/index.js +6 -1
  24. package/esm/src/column-interfaces.d.ts +44 -8
  25. package/esm/src/context.d.ts +31 -19
  26. package/esm/src/context.js +35 -42
  27. package/esm/src/data-api.js +17 -4
  28. package/esm/src/data-interfaces.d.ts +1 -1
  29. package/esm/src/data-providers/array-entity-data-provider.d.ts +1 -1
  30. package/esm/src/data-providers/array-entity-data-provider.js +1 -1
  31. package/esm/src/data-providers/rest-data-provider.d.ts +4 -15
  32. package/esm/src/data-providers/rest-data-provider.js +38 -23
  33. package/esm/src/data-providers/sql-database.d.ts +6 -3
  34. package/esm/src/data-providers/sql-database.js +57 -16
  35. package/esm/src/data-providers/web-sql-data-provider.d.ts +2 -0
  36. package/esm/src/data-providers/web-sql-data-provider.js +17 -8
  37. package/esm/src/entity.d.ts +2 -2
  38. package/esm/src/filter/filter-consumer-bridge-to-sql-request.d.ts +16 -16
  39. package/esm/src/filter/filter-consumer-bridge-to-sql-request.js +29 -21
  40. package/esm/src/filter/filter-interfaces.d.ts +5 -5
  41. package/esm/src/filter/filter-interfaces.js +31 -26
  42. package/esm/src/live-query/LiveQueryClient.d.ts +1 -19
  43. package/esm/src/live-query/LiveQueryClient.js +81 -50
  44. package/esm/src/live-query/SseSubscriptionClient.d.ts +4 -0
  45. package/esm/src/live-query/{EventSourceLiveQueryProvider.js → SseSubscriptionClient.js} +7 -6
  46. package/esm/src/live-query/SubscriptionChannel.d.ts +41 -0
  47. package/esm/src/live-query/{LiveQuerySubscriber.js → SubscriptionChannel.js} +40 -22
  48. package/esm/src/live-query/SubscriptionServer.d.ts +38 -0
  49. package/esm/src/live-query/{LiveQueryPublisher.js → SubscriptionServer.js} +60 -73
  50. package/esm/src/remult-proxy.js +44 -1
  51. package/esm/src/remult3/RepositoryImplementation.d.ts +8 -2
  52. package/esm/src/remult3/RepositoryImplementation.js +94 -30
  53. package/esm/src/remult3/remult3.d.ts +59 -6
  54. package/esm/src/remult3/remult3.js +1 -0
  55. package/esm/src/server-action.d.ts +1 -1
  56. package/esm/src/shared-tests/db-tests-setup.d.ts +1 -1
  57. package/esm/src/shared-tests/db-tests-setup.js +4 -3
  58. package/esm/src/shared-tests/db-tests.db-tests.js +55 -9
  59. package/esm/src/sql-command.d.ts +4 -2
  60. package/esm/src/tests/entityForCustomFilter.d.ts +6 -6
  61. package/esm/src/tests/entityForCustomFilter.js +20 -21
  62. package/esm/src/tests/frontend-database-tests-setup.spec.js +1 -2
  63. package/esm/src/tests/testHelper.spec.d.ts +2 -2
  64. package/esm/src/tests/testHelper.spec.js +1 -2
  65. package/esm/src/valueConverters.js +17 -7
  66. package/index.d.ts +4 -3
  67. package/index.js +7 -3
  68. package/live-query/ably.d.ts +6 -6
  69. package/live-query/ably.js +12 -12
  70. package/package.json +18 -9
  71. package/postgres/postgres-data-provider.d.ts +3 -1
  72. package/postgres/postgres-data-provider.js +13 -3
  73. package/postgres/schema-builder.d.ts +1 -1
  74. package/postgres/schema-builder.js +64 -50
  75. package/remult-express.d.ts +4 -22
  76. package/remult-express.js +39 -47
  77. package/remult-fastify.js +2 -2
  78. package/remult-fresh.js +1 -1
  79. package/remult-knex/index.d.ts +7 -31
  80. package/remult-knex/index.js +100 -53
  81. package/remult-mongo.d.ts +9 -2
  82. package/remult-mongo.js +39 -7
  83. package/remult-next.d.ts +11 -0
  84. package/remult-next.js +73 -0
  85. package/server/JsonEntityFileStorage.js +2 -2
  86. package/server/expressBridge.d.ts +20 -52
  87. package/server/expressBridge.js +68 -41
  88. package/server/index.d.ts +3 -1
  89. package/server/index.js +7 -2
  90. package/src/column-interfaces.d.ts +44 -8
  91. package/src/context.d.ts +31 -19
  92. package/src/context.js +39 -50
  93. package/src/data-api.js +18 -5
  94. package/src/data-interfaces.d.ts +1 -1
  95. package/src/data-providers/array-entity-data-provider.d.ts +1 -1
  96. package/src/data-providers/array-entity-data-provider.js +1 -1
  97. package/src/data-providers/rest-data-provider.d.ts +4 -15
  98. package/src/data-providers/rest-data-provider.js +48 -24
  99. package/src/data-providers/sql-database.d.ts +6 -3
  100. package/src/data-providers/sql-database.js +75 -15
  101. package/src/data-providers/web-sql-data-provider.d.ts +2 -0
  102. package/src/data-providers/web-sql-data-provider.js +16 -7
  103. package/src/entity.d.ts +2 -2
  104. package/src/filter/filter-consumer-bridge-to-sql-request.d.ts +16 -16
  105. package/src/filter/filter-consumer-bridge-to-sql-request.js +59 -50
  106. package/src/filter/filter-interfaces.d.ts +5 -5
  107. package/src/filter/filter-interfaces.js +31 -26
  108. package/src/live-query/LiveQueryClient.d.ts +1 -19
  109. package/src/live-query/LiveQueryClient.js +117 -64
  110. package/src/live-query/SseSubscriptionClient.d.ts +4 -0
  111. package/src/live-query/{EventSourceLiveQueryProvider.js → SseSubscriptionClient.js} +13 -12
  112. package/src/live-query/SubscriptionChannel.d.ts +41 -0
  113. package/src/live-query/{LiveQuerySubscriber.js → SubscriptionChannel.js} +51 -47
  114. package/src/live-query/SubscriptionServer.d.ts +38 -0
  115. package/src/live-query/SubscriptionServer.js +237 -0
  116. package/src/remult-proxy.js +137 -2
  117. package/src/remult3/RepositoryImplementation.d.ts +8 -2
  118. package/src/remult3/RepositoryImplementation.js +121 -34
  119. package/src/remult3/remult3.d.ts +59 -6
  120. package/src/remult3/remult3.js +1 -0
  121. package/src/server-action.d.ts +1 -1
  122. package/src/shared-tests/db-tests-setup.d.ts +1 -1
  123. package/src/shared-tests/db-tests-setup.js +5 -4
  124. package/src/shared-tests/db-tests.db-tests.js +101 -8
  125. package/src/sql-command.d.ts +4 -2
  126. package/src/tests/entityForCustomFilter.d.ts +6 -6
  127. package/src/tests/entityForCustomFilter.js +30 -31
  128. package/src/tests/frontend-database-tests-setup.spec.js +4 -5
  129. package/src/tests/testHelper.spec.d.ts +2 -2
  130. package/src/tests/testHelper.spec.js +4 -5
  131. package/src/valueConverters.js +17 -7
  132. package/esm/live-query/index.d.ts +0 -3
  133. package/esm/live-query/index.js +0 -3
  134. package/esm/src/backend-tests/backend-database-test-setup.backend-spec.d.ts +0 -5
  135. package/esm/src/backend-tests/backend-database-test-setup.backend-spec.js +0 -113
  136. package/esm/src/backend-tests/my-test.backend-spec.d.ts +0 -1
  137. package/esm/src/backend-tests/my-test.backend-spec.js +0 -59
  138. package/esm/src/backend-tests/test-http-server.backend-spec.d.ts +0 -6
  139. package/esm/src/backend-tests/test-http-server.backend-spec.js +0 -171
  140. package/esm/src/live-query/EventSourceLiveQueryProvider.d.ts +0 -4
  141. package/esm/src/live-query/LiveQueryPublisher.d.ts +0 -49
  142. package/esm/src/live-query/LiveQuerySubscriber.d.ts +0 -67
  143. package/live-query/index.d.ts +0 -3
  144. package/live-query/index.js +0 -10
  145. package/src/backend-tests/backend-database-test-setup.backend-spec.d.ts +0 -5
  146. package/src/backend-tests/backend-database-test-setup.backend-spec.js +0 -231
  147. package/src/backend-tests/my-test.backend-spec.d.ts +0 -1
  148. package/src/backend-tests/my-test.backend-spec.js +0 -160
  149. package/src/backend-tests/test-http-server.backend-spec.d.ts +0 -6
  150. package/src/backend-tests/test-http-server.backend-spec.js +0 -342
  151. package/src/live-query/EventSourceLiveQueryProvider.d.ts +0 -4
  152. package/src/live-query/LiveQueryPublisher.d.ts +0 -49
  153. package/src/live-query/LiveQueryPublisher.js +0 -248
  154. package/src/live-query/LiveQuerySubscriber.d.ts +0 -67
@@ -1,78 +1,17 @@
1
- import { v4 as uuid } from 'uuid';
2
- import { findOptionsFromJson, findOptionsToJson } from '../data-providers/rest-data-provider';
3
- export class LiveQueryStorageInMemoryImplementation {
4
- constructor() {
5
- this.debugFileSaver = (x) => { };
6
- this.queries = [];
7
- }
8
- debug() {
9
- this.debugFileSaver(this.queries);
10
- }
11
- async keepAliveAndReturnUnknownIds(ids) {
12
- const result = [];
13
- for (const id of ids) {
14
- let q = this.queries.find(q => q.id === id);
15
- if (q) {
16
- q.lastUsed = new Date().toISOString();
17
- }
18
- else
19
- result.push(id);
20
- }
21
- this.debug();
22
- return result;
23
- }
24
- store(query) {
25
- this.queries.push({ ...query, lastUsed: new Date().toISOString() });
26
- this.debug();
27
- }
28
- remove(id) {
29
- this.queries = this.queries.filter(q => q.id !== id);
30
- this.debug();
31
- }
32
- async provideListeners(entityKey, handle) {
33
- let d = new Date();
34
- d.setMinutes(d.getMinutes() - 5);
35
- this.queries = this.queries.filter(x => x.lastUsed > d.toISOString());
36
- for (const q of this.queries) {
37
- if (q.entityKey === entityKey) {
38
- await handle({
39
- query: q,
40
- setLastIds: async (ids) => { q.lastIds = ids; },
41
- });
42
- }
43
- }
44
- this.debug();
45
- }
46
- }
1
+ import { findOptionsFromJson } from '../data-providers/rest-data-provider';
2
+ /* @internal*/
47
3
  export class LiveQueryPublisher {
48
- constructor(dispatcher, storage, performWithRequest) {
49
- this.dispatcher = dispatcher;
50
- this.storage = storage;
4
+ constructor(subscriptionServer, liveQueryStorage, performWithRequest) {
5
+ this.subscriptionServer = subscriptionServer;
6
+ this.liveQueryStorage = liveQueryStorage;
51
7
  this.performWithRequest = performWithRequest;
52
8
  this.debugFileSaver = (x) => { };
53
9
  }
54
- stopLiveQuery(id) {
55
- this.storage.remove(id);
56
- }
57
- sendChannelMessage(channel, message) {
58
- this.dispatcher.sendChannelMessage(channel, message);
59
- }
60
- defineLiveQueryChannel(serializeRequest, entityKey, findOptions, ids, userId, repo) {
61
- const id = `users:${userId}:queries:${uuid()}`;
62
- this.storage.store({
63
- requestJson: serializeRequest(),
64
- entityKey,
65
- id,
66
- findOptionsJson: findOptionsToJson(findOptions, repo.metadata),
67
- lastIds: ids
68
- });
69
- return id;
70
- }
71
- runPromise(p) {
72
- }
10
+ runPromise(p) { }
73
11
  itemChanged(entityKey, changes) {
74
- //TODO - optimize so that the user will get their messages first. Based on user id
75
- this.runPromise(this.storage.provideListeners(entityKey, async ({ query, setLastIds }) => {
12
+ //TODO 2 - optimize so that the user will get their messages first. Based on user id
13
+ this.runPromise(this.liveQueryStorage().forEach(entityKey, async ({ query: q, setData }) => {
14
+ let query = { ...q.data };
76
15
  await this.performWithRequest(query.requestJson, entityKey, async (repo) => {
77
16
  const messages = [];
78
17
  const currentItems = await repo.find(findOptionsFromJson(query.findOptionsJson, repo.metadata));
@@ -107,15 +46,63 @@ export class LiveQueryPublisher {
107
46
  }
108
47
  }
109
48
  this.debugFileSaver({
110
- query: query.id,
49
+ query: q.id,
111
50
  currentIds,
112
51
  changes,
113
52
  lastIds: query.lastIds,
114
53
  messages
115
54
  });
116
- await setLastIds(currentIds);
117
- this.dispatcher.sendChannelMessage(query.id, messages);
55
+ query.lastIds = currentIds;
56
+ await setData(query);
57
+ if (messages.length > 0)
58
+ this.subscriptionServer().publishMessage(q.id, messages);
118
59
  });
119
60
  }));
120
61
  }
121
62
  }
63
+ export class InMemoryLiveQueryStorage {
64
+ constructor() {
65
+ this.debugFileSaver = (x) => { };
66
+ this.queries = [];
67
+ this.removeCountForTesting = 0;
68
+ }
69
+ debug() {
70
+ this.debugFileSaver(this.queries);
71
+ }
72
+ async keepAliveAndReturnUnknownQueryIds(ids) {
73
+ const result = [];
74
+ for (const id of ids) {
75
+ let q = this.queries.find(q => q.id === id);
76
+ if (q) {
77
+ q.lastUsed = new Date().toISOString();
78
+ }
79
+ else
80
+ result.push(id);
81
+ }
82
+ this.debug();
83
+ return result;
84
+ }
85
+ add(query) {
86
+ this.queries.push({ ...query, lastUsed: new Date().toISOString() });
87
+ this.debug();
88
+ }
89
+ remove(id) {
90
+ this.queries = this.queries.filter(q => q.id !== id);
91
+ this.removeCountForTesting++;
92
+ this.debug();
93
+ }
94
+ async forEach(entityKey, handle) {
95
+ let d = new Date();
96
+ d.setMinutes(d.getMinutes() - 5);
97
+ this.queries = this.queries.filter(x => x.lastUsed > d.toISOString());
98
+ for (const q of this.queries) {
99
+ if (q.entityKey === entityKey) {
100
+ await handle({
101
+ query: q,
102
+ setData: async (data) => { q.data = data; },
103
+ });
104
+ }
105
+ }
106
+ this.debug();
107
+ }
108
+ }
@@ -3,15 +3,47 @@ export class RemultProxy {
3
3
  constructor() {
4
4
  /*@internal*/
5
5
  this.remultFactory = () => RemultProxy.defaultRemult;
6
- this.repo = (...args) => this.remultFactory().repo(...args);
6
+ //@ts-ignore
7
+ this.repo = (...args) => {
8
+ let self = this;
9
+ return {
10
+ addEventListener: (...args2) => self.remultFactory().repo(...args).addEventListener(...args2),
11
+ count: (...args2) => self.remultFactory().repo(...args).count(...args2),
12
+ create: (...args2) => self.remultFactory().repo(...args).create(...args2),
13
+ delete: (args2) => self.remultFactory().repo(...args).delete(args2),
14
+ find: (...args2) => self.remultFactory().repo(...args).find(...args2),
15
+ findFirst: (...args2) => self.remultFactory().repo(...args).findFirst(...args2),
16
+ findId: (...args2) => self.remultFactory().repo(...args).findId(...args2),
17
+ fromJson: (...args2) => self.remultFactory().repo(...args).fromJson(...args2),
18
+ getEntityRef: (...args2) => self.remultFactory().repo(...args).getEntityRef(...args2),
19
+ insert: (args2) => self.remultFactory().repo(...args).insert(args2),
20
+ liveQuery: (...args2) => self.remultFactory().repo(...args).liveQuery(...args2),
21
+ get metadata() {
22
+ return self.remultFactory().repo(...args).metadata;
23
+ },
24
+ query: (...args2) => self.remultFactory().repo(...args).query(...args2),
25
+ save: (args2) => self.remultFactory().repo(...args).save(args2),
26
+ update: (...args2) => self.remultFactory().repo(...args).update(...args2),
27
+ };
28
+ };
7
29
  }
30
+ /* @internal*/
8
31
  get liveQuerySubscriber() { return this.remultFactory().liveQuerySubscriber; }
9
32
  ;
33
+ /* @internal*/
10
34
  set liveQuerySubscriber(val) { this.remultFactory().liveQuerySubscriber = val; }
11
35
  ;
36
+ /* @internal*/
37
+ get liveQueryStorage() { return this.remultFactory().liveQueryStorage; }
38
+ ;
39
+ /* @internal*/
40
+ set liveQueryStorage(val) { this.remultFactory().liveQueryStorage = val; }
41
+ ;
42
+ /* @internal*/
12
43
  get liveQueryPublisher() {
13
44
  return this.remultFactory().liveQueryPublisher;
14
45
  }
46
+ /* @internal*/
15
47
  set liveQueryPublisher(val) {
16
48
  this.remultFactory().liveQueryPublisher = val;
17
49
  }
@@ -24,6 +56,7 @@ export class RemultProxy {
24
56
  get dataProvider() { return this.remultFactory().dataProvider; }
25
57
  ;
26
58
  set dataProvider(provider) { this.remultFactory().dataProvider = provider; }
59
+ /*@internal*/
27
60
  get repCache() { return this.remultFactory().repCache; }
28
61
  ;
29
62
  authenticated() {
@@ -38,6 +71,10 @@ export class RemultProxy {
38
71
  clearAllCache() {
39
72
  return this.remultFactory().clearAllCache();
40
73
  }
74
+ /*@internal*/
75
+ resetFactory() {
76
+ this.remultFactory = () => RemultProxy.defaultRemult;
77
+ }
41
78
  get user() {
42
79
  return this.remultFactory().user;
43
80
  }
@@ -50,5 +87,11 @@ export class RemultProxy {
50
87
  set apiClient(client) {
51
88
  this.remultFactory().apiClient = client;
52
89
  }
90
+ get subscriptionServer() {
91
+ return this.remultFactory().subscriptionServer;
92
+ }
93
+ set subscriptionServer(value) {
94
+ this.remultFactory().subscriptionServer = value;
95
+ }
53
96
  }
54
97
  export const remult = new RemultProxy();
@@ -41,6 +41,7 @@ export declare class RepositoryImplementation<entityType> implements Repository<
41
41
  private getRefForExistingRow;
42
42
  save(item: Partial<OmitEB<entityType>>[]): Promise<entityType[]>;
43
43
  save(item: Partial<OmitEB<entityType>>): Promise<entityType>;
44
+ liveQuery(options?: FindOptions<entityType>): any;
44
45
  find(options: FindOptions<entityType>): Promise<entityType[]>;
45
46
  buildEntityDataProviderFindOptions(options: FindOptions<entityType>): Promise<EntityDataProviderFindOptions>;
46
47
  private mapRawDataToResult;
@@ -51,7 +52,6 @@ export declare class RepositoryImplementation<entityType> implements Repository<
51
52
  create(item?: Partial<OmitEB<entityType>>): entityType;
52
53
  fromJson(json: any, newRow?: boolean): Promise<entityType>;
53
54
  findId(id: any, options?: FindFirstOptionsBase<entityType>): Promise<entityType>;
54
- private translateWhereToFilter;
55
55
  }
56
56
  export declare function __updateEntityBasedOnWhere<T>(entityDefs: EntityMetadata<T>, where: EntityFilter<T>, r: T): void;
57
57
  export declare type EntityOptionsFactory = (remult: Remult) => EntityOptions;
@@ -178,7 +178,6 @@ export declare class columnDefsImpl implements FieldMetadata {
178
178
  private settings;
179
179
  private entityDefs;
180
180
  constructor(settings: FieldOptions, entityDefs: EntityFullInfo<any>, remult: Remult);
181
- dbNamePromise: Promise<string>;
182
181
  getDbName(): Promise<string>;
183
182
  options: FieldOptions<any, any>;
184
183
  target: ClassType<any>;
@@ -220,7 +219,10 @@ export declare class Fields {
220
219
  static integer<entityType = any>(...options: (FieldOptions<entityType, Number> | ((options: FieldOptions<entityType, Number>, remult: Remult) => void))[]): (target: any, key: any, c?: any) => void;
221
220
  static autoIncrement<entityType = any>(...options: (FieldOptions<entityType, Number> | ((options: FieldOptions<entityType, Number>, remult: Remult) => void))[]): (target: any, key: any, c?: any) => void;
222
221
  static number<entityType = any>(...options: (FieldOptions<entityType, Number> | ((options: FieldOptions<entityType, Number>, remult: Remult) => void))[]): (target: any, key: any, c?: any) => void;
222
+ static createdAt<entityType = any>(...options: (FieldOptions<entityType, Date> | ((options: FieldOptions<entityType, Date>, remult: Remult) => void))[]): (target: any, key: any, c?: any) => void;
223
+ static updatedAt<entityType = any>(...options: (FieldOptions<entityType, Date> | ((options: FieldOptions<entityType, Date>, remult: Remult) => void))[]): (target: any, key: any, c?: any) => void;
223
224
  static uuid<entityType = any>(...options: (FieldOptions<entityType, string> | ((options: FieldOptions<entityType, string>, remult: Remult) => void))[]): (target: any, key: any, c?: any) => void;
225
+ static cuid<entityType = any>(...options: (FieldOptions<entityType, string> | ((options: FieldOptions<entityType, string>, remult: Remult) => void))[]): (target: any, key: any, c?: any) => void;
224
226
  static string<entityType = any>(...options: (StringFieldOptions<entityType> | ((options: StringFieldOptions<entityType>, remult: Remult) => void))[]): (target: any, key: any, c?: any) => void;
225
227
  static boolean<entityType = any>(...options: (FieldOptions<entityType, boolean> | ((options: FieldOptions<entityType, boolean>, remult: Remult) => void))[]): (target: any, key: any, c?: any) => void;
226
228
  }
@@ -323,4 +325,8 @@ declare class SubscribableImp implements Subscribable {
323
325
  reportObserved: () => void;
324
326
  }): Unobserve;
325
327
  }
328
+ export declare function getEntityMetadata<entityType>(entity: EntityMetadataOverloads<entityType>): EntityMetadata<entityType>;
329
+ export declare function getRepository<entityType>(entity: RepositoryOverloads<entityType>): Repository<entityType>;
330
+ export declare type EntityMetadataOverloads<entityType> = Repository<entityType> | EntityMetadata<entityType> | ClassType<entityType>;
331
+ export declare type RepositoryOverloads<entityType> = Repository<entityType> | ClassType<entityType>;
326
332
  export {};
@@ -3,10 +3,11 @@ import { allEntities, Remult, isBackend, queryConfig as queryConfig, setControll
3
3
  import { entityFilterToJson, Filter } from "../filter/filter-interfaces";
4
4
  import { Sort } from "../sort";
5
5
  import { v4 as uuid } from 'uuid';
6
+ import cuid from 'cuid';
6
7
  import { ValueConverters } from "../valueConverters";
7
8
  import { filterHelper } from "../filter/filter-interfaces";
8
9
  import { assign } from "../../assign";
9
- import { remult as defaultRemult } from "../remult-proxy";
10
+ import { remult as defaultRemult, RemultProxy } from "../remult-proxy";
10
11
  import { getId } from "./getId";
11
12
  //import { remult } from "../remult-proxy";
12
13
  let classValidatorValidate = undefined;
@@ -199,6 +200,25 @@ export class RepositoryImplementation {
199
200
  }
200
201
  }
201
202
  }
203
+ liveQuery(options) {
204
+ if (!options)
205
+ options = {};
206
+ return {
207
+ subscribe: (l) => {
208
+ let listener = l;
209
+ if (typeof l === "function") {
210
+ listener = {
211
+ next: l,
212
+ complete: () => { },
213
+ error: () => { }
214
+ };
215
+ }
216
+ listener.error ??= () => { };
217
+ listener.complete ??= () => { };
218
+ return this.remult.liveQuerySubscriber.subscribe(this, options, listener);
219
+ }
220
+ };
221
+ }
202
222
  async find(options) {
203
223
  Remult.onFind(this._info, options);
204
224
  if (!options)
@@ -363,6 +383,7 @@ export class RepositoryImplementation {
363
383
  where: this.metadata.idMetadata.getIdFilter(id),
364
384
  });
365
385
  }
386
+ /* @internal*/
366
387
  async translateWhereToFilter(where) {
367
388
  if (this.metadata.options.backendPrefilter && isBackend()) {
368
389
  let z = where;
@@ -373,7 +394,7 @@ export class RepositoryImplementation {
373
394
  };
374
395
  }
375
396
  let r = await Filter.fromEntityFilter(this.metadata, where);
376
- if (r && !this.dataProvider.supportsCustomFilter) {
397
+ if (r && !this.dataProvider.supportsrawFilter) {
377
398
  r = await Filter.translateCustomWhere(r, this.metadata, this.remult);
378
399
  }
379
400
  return r;
@@ -460,6 +481,12 @@ class rowHelperBase {
460
481
  this._isLoading = false;
461
482
  this.lookups = new Map();
462
483
  this.originalValues = {};
484
+ {
485
+ let fac = remult;
486
+ if (fac != null && fac.remultFactory) {
487
+ remult = fac.remultFactory();
488
+ }
489
+ }
463
490
  for (const col of columnsInfo) {
464
491
  let ei = getEntitySettings(col.valueType, false);
465
492
  if (ei && remult) {
@@ -1151,24 +1178,23 @@ export class columnDefsImpl {
1151
1178
  this.inputType = this.valueConverter.inputType;
1152
1179
  this.caption = buildCaption(settings.caption, settings.key, remult);
1153
1180
  }
1154
- getDbName() {
1155
- if (this.dbNamePromise)
1156
- return this.dbNamePromise;
1157
- this.dbNamePromise = (async () => {
1181
+ async getDbName() {
1182
+ try {
1158
1183
  if (this.settings.sqlExpression) {
1184
+ let result;
1159
1185
  if (typeof this.settings.sqlExpression === "function") {
1160
- return this.settings.sqlExpression(this.entityDefs);
1186
+ result = await this.settings.sqlExpression(this.entityDefs);
1161
1187
  }
1162
1188
  else
1163
- return this.settings.sqlExpression;
1189
+ result = this.settings.sqlExpression;
1190
+ if (!result)
1191
+ return this.settings.dbName;
1192
+ return result;
1164
1193
  }
1165
1194
  return this.settings.dbName;
1166
- })().then(x => {
1167
- if (x)
1168
- return x;
1169
- return this.settings.dbName;
1170
- });
1171
- return this.dbNamePromise;
1195
+ }
1196
+ finally {
1197
+ }
1172
1198
  }
1173
1199
  get dbName() {
1174
1200
  let result;
@@ -1282,7 +1308,7 @@ class EntityFullInfo {
1282
1308
  if (typeof this.options.sqlExpression === "string")
1283
1309
  this.dbNamePromise = Promise.resolve(this.options.sqlExpression);
1284
1310
  else if (typeof this.options.sqlExpression === "function") {
1285
- let r = this.options.sqlExpression(this.fields);
1311
+ let r = this.options.sqlExpression(this);
1286
1312
  if (r instanceof Promise)
1287
1313
  this.dbNamePromise = r;
1288
1314
  else if (r)
@@ -1333,10 +1359,39 @@ export class Fields {
1333
1359
  static number(...options) {
1334
1360
  return Field(() => Number, ...options);
1335
1361
  }
1362
+ static createdAt(...options) {
1363
+ return Field(() => Date, {
1364
+ saving: (_, ref) => {
1365
+ if (getEntityRef(_).isNew())
1366
+ ref.value = new Date();
1367
+ }
1368
+ }, ...options);
1369
+ }
1370
+ static updatedAt(...options) {
1371
+ return Field(() => Date, {
1372
+ saving: (_, ref) => {
1373
+ ref.value = new Date();
1374
+ }
1375
+ }, ...options);
1376
+ }
1336
1377
  static uuid(...options) {
1337
1378
  return Field(() => String, {
1338
1379
  allowApiUpdate: false,
1339
- defaultValue: () => uuid()
1380
+ defaultValue: () => uuid(),
1381
+ saving: (_, r) => {
1382
+ if (!r.value)
1383
+ r.value = uuid();
1384
+ }
1385
+ }, ...options);
1386
+ }
1387
+ static cuid(...options) {
1388
+ return Field(() => String, {
1389
+ allowApiUpdate: false,
1390
+ defaultValue: () => cuid(),
1391
+ saving: (_, r) => {
1392
+ if (!r.value)
1393
+ r.value = cuid();
1394
+ }
1340
1395
  }, ...options);
1341
1396
  }
1342
1397
  static string(...options) {
@@ -1353,7 +1408,7 @@ export function ValueListFieldType(...options) {
1353
1408
  return (type) => {
1354
1409
  FieldType(o => {
1355
1410
  o.valueConverter = ValueListInfo.get(type),
1356
- o.displayValue = (item, val) => val.caption;
1411
+ o.displayValue = (item, val) => val?.caption;
1357
1412
  }, ...options)(type);
1358
1413
  };
1359
1414
  }
@@ -1613,12 +1668,12 @@ export function decorateColumnSettings(settings, remult) {
1613
1668
  */
1614
1669
  export function Entity(key, ...options) {
1615
1670
  return target => {
1616
- for (const customFilterMember in target) {
1617
- if (Object.prototype.hasOwnProperty.call(target, customFilterMember)) {
1618
- const element = target[customFilterMember];
1619
- if (element?.customFilterInfo?.customFilterTranslator) {
1620
- if (!element.customFilterInfo.key)
1621
- element.customFilterInfo.key = customFilterMember;
1671
+ for (const rawFilterMember in target) {
1672
+ if (Object.prototype.hasOwnProperty.call(target, rawFilterMember)) {
1673
+ const element = target[rawFilterMember];
1674
+ if (element?.rawFilterInfo?.rawFilterTranslator) {
1675
+ if (!element.rawFilterInfo.key)
1676
+ element.rawFilterInfo.key = rawFilterMember;
1622
1677
  }
1623
1678
  }
1624
1679
  }
@@ -1687,13 +1742,6 @@ class QueryResultImpl {
1687
1742
  this.options.pageSize = queryConfig.defaultPageSize;
1688
1743
  }
1689
1744
  }
1690
- subscribe(onResult) {
1691
- return this.repo.remult.liveQuerySubscriber.subscribe(this.repo, {
1692
- load: this.options.load,
1693
- orderBy: this.options.orderBy,
1694
- where: this.options.where
1695
- }, onResult);
1696
- }
1697
1745
  async getPage(page) {
1698
1746
  if (page < 1)
1699
1747
  page = 1;
@@ -1813,3 +1861,19 @@ class SubscribableImp {
1813
1861
  return () => this._subscribers = this._subscribers.filter(x => x != list);
1814
1862
  }
1815
1863
  }
1864
+ export function getEntityMetadata(entity) {
1865
+ if (entity.metadata)
1866
+ return entity.metadata;
1867
+ const settings = getEntitySettings(entity, false);
1868
+ if (settings) {
1869
+ return RemultProxy.defaultRemult.repo(entity).metadata;
1870
+ }
1871
+ return entity;
1872
+ }
1873
+ export function getRepository(entity) {
1874
+ const settings = getEntitySettings(entity, false);
1875
+ if (settings) {
1876
+ return RemultProxy.defaultRemult.repo(entity);
1877
+ }
1878
+ return entity;
1879
+ }
@@ -1,7 +1,8 @@
1
1
  import { ClassType } from "../../classType";
2
2
  import { FieldMetadata } from "../column-interfaces";
3
3
  import { Unobserve } from "../context";
4
- import { EntityOptions as EntityOptions } from "../entity";
4
+ import { LiveQueryChange, SubscriptionListener, Unsubscribe } from "../live-query/SubscriptionChannel";
5
+ import { EntityOptions } from "../entity";
5
6
  import { SortSegment } from "../sort";
6
7
  import { entityEventListener } from "../__EntityValueProvider";
7
8
  export interface EntityRef<entityType> extends Subscribable {
@@ -95,18 +96,57 @@ export interface IdMetadata<entityType = any> {
95
96
  isIdField(col: FieldMetadata): boolean;
96
97
  createIdInFilter(items: entityType[]): EntityFilter<entityType>;
97
98
  }
99
+ /** Metadata for an `Entity`, this metadata can be used in the user interface to provide a richer UI experience */
98
100
  export interface EntityMetadata<entityType = any> {
99
- readonly idMetadata: IdMetadata<entityType>;
101
+ /** The Entity's key also used as it's url */
100
102
  readonly key: string;
103
+ /** Metadata for the Entity's fields */
101
104
  readonly fields: FieldsMetadata<entityType>;
105
+ /** A human readable caption for the entity. Can be used to achieve a consistent caption for a field throughout the app
106
+ * @example
107
+ * <h1>Create a new item in {taskRepo.metadata.caption}</h1>
108
+ */
102
109
  readonly caption: string;
110
+ /** The options send to the `Entity`'s decorator */
103
111
  readonly options: EntityOptions;
112
+ /** The class type of the entity */
104
113
  readonly entityType: ClassType<entityType>;
114
+ /** true if the current user is allowed to update an entity instance
115
+ * @example
116
+ * const taskRepo = remult.repo(Task);
117
+ * if (taskRepo.metadata.apiUpdateAllowed){
118
+ * //Allow user to edit the entity
119
+ * }
120
+ */
105
121
  readonly apiUpdateAllowed: boolean;
122
+ /** true if the current user is allowed to read from entity
123
+ * @example
124
+ * const taskRepo = remult.repo(Task);
125
+ * if (taskRepo.metadata.apiReadAllowed){
126
+ * taskRepo.find()
127
+ * }
128
+ */
106
129
  readonly apiReadAllowed: boolean;
130
+ /** true if the current user is allowed to delete an entity instance
131
+ * @example
132
+ * const taskRepo = remult.repo(Task);
133
+ * if (taskRepo.metadata.apiDeleteAllowed){
134
+ * //display delete button
135
+ * }
136
+ */
107
137
  readonly apiDeleteAllowed: boolean;
138
+ /** true if the current user is allowed to create an entity instance
139
+ * @example
140
+ * const taskRepo = remult.repo(Task);
141
+ * if (taskRepo.metadata.apiInsertAllowed){
142
+ * //display insert button
143
+ * }
144
+ */
108
145
  readonly apiInsertAllowed: boolean;
146
+ /** Returns the dbName - based on it's `dbName` option and it's `sqlExpression` option */
109
147
  getDbName(): Promise<string>;
148
+ /** Metadata for the Entity's id */
149
+ readonly idMetadata: IdMetadata<entityType>;
110
150
  }
111
151
  export declare type OmitEB<T> = Omit<T, keyof import('./RepositoryImplementation').EntityBase>;
112
152
  export declare type idType<entityType> = entityType extends {
@@ -118,6 +158,8 @@ export declare type idType<entityType> = entityType extends {
118
158
  export interface Repository<entityType> {
119
159
  /** returns a result array based on the provided options */
120
160
  find(options?: FindOptions<entityType>): Promise<entityType[]>;
161
+ /** returns a result array based on the provided options */
162
+ liveQuery(options?: FindOptions<entityType>): LiveQuery<entityType>;
121
163
  /** returns the first item that matchers the `where` condition
122
164
  * @example
123
165
  * await taskRepo.findFirst({ completed:false })
@@ -131,7 +173,7 @@ export interface Repository<entityType> {
131
173
  *
132
174
  * It also has it's own paging mechanism that can be used n paging scenarios.
133
175
  *
134
- * The `query` method doesn't return an array (as the `find` method) and instead returns an `iteratable` `QueryResult` object
176
+ * The `query` method doesn't return an array (as the `find` method) and instead returns an `iterable` `QueryResult` object
135
177
  * which supports iterations using the JavaScript `for await` statement.
136
178
  * @example
137
179
  * for await (const task of taskRepo.query()) {
@@ -181,10 +223,21 @@ export interface Repository<entityType> {
181
223
  fromJson(x: any, isNew?: boolean): Promise<entityType>;
182
224
  /** returns an `entityRef` for an item returned by `create`, `find` etc... */
183
225
  getEntityRef(item: entityType): EntityRef<entityType>;
184
- /**The metadata for the `entity` */
226
+ /**The metadata for the `entity`
227
+ * @See [EntityMetadata](https://remult.dev/docs/ref_entitymetadata.html)
228
+ */
185
229
  metadata: EntityMetadata<entityType>;
186
230
  addEventListener(listener: entityEventListener<entityType>): Unobserve;
187
231
  }
232
+ export interface LiveQuery<entityType> {
233
+ subscribe(next: (info: LiveQueryChangeInfo<entityType>) => void): Unsubscribe;
234
+ subscribe(listener: Partial<SubscriptionListener<LiveQueryChangeInfo<entityType>>>): Unsubscribe;
235
+ }
236
+ export interface LiveQueryChangeInfo<entityType> {
237
+ items: entityType[];
238
+ changes: LiveQueryChange[];
239
+ applyChanges(prevState: entityType[]): entityType[];
240
+ }
188
241
  export interface FindOptions<entityType> extends FindOptionsBase<entityType> {
189
242
  /** Determines the number of rows returned by the request, on the browser the default is 100 rows
190
243
  * @example
@@ -226,6 +279,8 @@ export declare type EntityFilter<entityType> = {
226
279
  export declare type ValueFilter<valueType> = valueType | valueType[] | {
227
280
  $ne?: valueType | valueType[];
228
281
  "!="?: valueType | valueType[];
282
+ $in?: valueType[];
283
+ $nin?: valueType[];
229
284
  };
230
285
  export declare type ComparisonValueFilter<valueType> = ValueFilter<valueType> & {
231
286
  $gt?: valueType;
@@ -300,8 +355,6 @@ export interface QueryResult<entityType> {
300
355
  getPage(pageNumber?: number): Promise<entityType[]>;
301
356
  /** Performs an operation on all the items matching the query criteria */
302
357
  forEach(what: (item: entityType) => Promise<any>): Promise<number>;
303
- /**@Experimental */
304
- subscribe(onResult: (reducer: (prevState: entityType[]) => entityType[]) => void): VoidFunction;
305
358
  }
306
359
  /** An interface used to paginating using the `query` method in the `Repository` object */
307
360
  export interface Paginator<entityType> {
@@ -1 +1,2 @@
1
+ ;
1
2
  export {};
@@ -21,7 +21,7 @@ export declare abstract class Action<inParam, outParam> implements ActionInterfa
21
21
  }
22
22
  export declare class ForbiddenError extends Error {
23
23
  constructor();
24
- isForbiddenError: boolean;
24
+ isForbiddenError: true;
25
25
  }
26
26
  export declare class myServerAction extends Action<inArgs, result> {
27
27
  private types;
@@ -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): void;
9
+ export declare function addDatabaseToTest(tester: dbTestMethodSignature): dbTestMethodSignature;
10
10
  export declare function testInMemory(key: string, what: dbTestWhatSignature, focus?: boolean): void;
11
11
  export declare type dbTestWhatSignature = (db: {
12
12
  db: DataProvider;
@@ -2,8 +2,9 @@ import { Remult } from "../context";
2
2
  import { InMemoryDataProvider } from "../data-providers/in-memory-database";
3
3
  import { Categories } from "../tests/remult-3-entities";
4
4
  export function itWithFocus(key, what, focus = false) {
5
- if (focus)
5
+ if (focus) {
6
6
  fit(key, what);
7
+ }
7
8
  else
8
9
  it(key, what);
9
10
  }
@@ -22,12 +23,12 @@ export function addDatabaseToTest(tester) {
22
23
  test(tester);
23
24
  }
24
25
  databasesTesters.push(tester);
26
+ return tester;
25
27
  }
26
28
  export function testInMemory(key, what, focus = false) {
27
29
  itWithFocus(key + " - in memory", async () => {
28
- let remult = new Remult();
29
30
  let db = new InMemoryDataProvider();
30
- remult.dataProvider = (db);
31
+ let remult = new Remult(db);
31
32
  await what({ db, remult, createEntity: async (x) => remult.repo(x) });
32
33
  }, focus);
33
34
  }