remult 0.17.0-exp.2 → 0.17.0-exp.3
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.
- package/esm/postgres/schema-builder.js +4 -4
- package/esm/remult-express.d.ts +2 -2
- package/esm/remult-express.js +6 -8
- package/esm/remult-knex/index.js +2 -2
- package/esm/server/expressBridge.d.ts +1 -1
- package/esm/server/expressBridge.js +2 -2
- package/esm/src/context.d.ts +1 -1
- package/esm/src/context.js +1 -1
- package/esm/src/data-api.js +18 -8
- package/esm/src/data-providers/sql-database.js +1 -1
- package/esm/src/data-providers/web-sql-data-provider.js +1 -1
- package/esm/src/live-query/EventSourceLiveQueryProvider.d.ts +2 -2
- package/esm/src/live-query/EventSourceLiveQueryProvider.js +9 -2
- package/esm/src/live-query/LiveQuery.d.ts +1 -1
- package/esm/src/live-query/LiveQuery.js +3 -2
- package/esm/src/live-query/LiveQueryPublisher.d.ts +33 -0
- package/esm/src/live-query/LiveQueryPublisher.js +102 -0
- package/esm/src/live-query/LiveQuerySubscriber.d.ts +67 -0
- package/esm/src/live-query/LiveQuerySubscriber.js +238 -0
- package/esm/src/remult3/RepositoryImplementation.js +0 -1
- package/esm/src/server-action.d.ts +4 -0
- package/esm/src/server-action.js +1 -1
- package/esm/src/valueConverters.js +1 -1
- package/package.json +1 -1
- package/postgres/schema-builder.js +4 -4
- package/remult-express.d.ts +2 -2
- package/remult-express.js +8 -10
- package/remult-knex/index.js +2 -2
- package/server/expressBridge.d.ts +1 -1
- package/server/expressBridge.js +2 -2
- package/src/context.d.ts +1 -1
- package/src/context.js +2 -2
- package/src/data-api.js +43 -19
- package/src/data-providers/sql-database.js +1 -1
- package/src/data-providers/web-sql-data-provider.js +1 -1
- package/src/live-query/EventSourceLiveQueryProvider.d.ts +2 -2
- package/src/live-query/EventSourceLiveQueryProvider.js +10 -3
- package/src/live-query/LiveQuery.d.ts +1 -1
- package/src/live-query/LiveQuery.js +8 -7
- package/src/live-query/LiveQueryPublisher.d.ts +33 -0
- package/src/live-query/LiveQueryPublisher.js +201 -0
- package/src/live-query/LiveQuerySubscriber.d.ts +67 -0
- package/src/live-query/LiveQuerySubscriber.js +332 -0
- package/src/remult3/RepositoryImplementation.js +0 -1
- package/src/server-action.d.ts +4 -0
- package/src/server-action.js +2 -1
- package/src/valueConverters.js +1 -1
|
@@ -43,7 +43,7 @@ export class PostgresSchemaBuilder {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
async verifyStructureOfAllEntities(remult) {
|
|
46
|
-
console.log("start verify structure");
|
|
46
|
+
console.log("start verify structure"); //keep me
|
|
47
47
|
for (const entityClass of allEntities) {
|
|
48
48
|
let entity = remult.repo(entityClass).metadata;
|
|
49
49
|
let e = await getDbNameProvider(entity);
|
|
@@ -56,7 +56,7 @@ export class PostgresSchemaBuilder {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
catch (err) {
|
|
59
|
-
console.log("failed verify structure of " + e.entityName + " ", err);
|
|
59
|
+
/*keep me */ console.log("failed verify structure of " + e.entityName + " ", err);
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
}
|
|
@@ -102,7 +102,7 @@ export class PostgresSchemaBuilder {
|
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
catch (err) {
|
|
105
|
-
console.
|
|
105
|
+
console.error(err);
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
108
|
async verifyAllColumns(entity) {
|
|
@@ -122,7 +122,7 @@ export class PostgresSchemaBuilder {
|
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
catch (err) {
|
|
125
|
-
console.
|
|
125
|
+
console.error(err);
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
}
|
package/esm/remult-express.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as express from 'express';
|
|
2
2
|
import { RemultServer, RemultServerOptions } from './server/expressBridge';
|
|
3
3
|
import { Remult } from './src/context';
|
|
4
|
-
import { AMessageChannel, ChannelSubscribe } from './src/live-query/
|
|
5
|
-
import { ServerEventDispatcher, ServerEventMessage } from './src/live-query/
|
|
4
|
+
import { AMessageChannel, ChannelSubscribe } from './src/live-query/LiveQuerySubscriber';
|
|
5
|
+
import { ServerEventDispatcher, ServerEventMessage } from './src/live-query/LiveQueryPublisher';
|
|
6
6
|
export declare function remultExpress(options?: RemultServerOptions<express.Request> & {
|
|
7
7
|
bodyParser?: boolean;
|
|
8
8
|
bodySizeLimit?: string;
|
package/esm/remult-express.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import * as express from 'express';
|
|
2
2
|
import { createRemultServer } from './server/expressBridge';
|
|
3
|
-
import { streamUrl } from './src/live-query/
|
|
4
|
-
import { LiveQueryPublisher } from './src/live-query/
|
|
5
|
-
import { remult } from './src/remult-proxy';
|
|
3
|
+
import { streamUrl } from './src/live-query/LiveQuerySubscriber';
|
|
4
|
+
import { LiveQueryPublisher } from './src/live-query/LiveQueryPublisher';
|
|
6
5
|
export function remultExpress(options) {
|
|
7
6
|
let app = express.Router();
|
|
8
7
|
if (!options) {
|
|
@@ -24,7 +23,9 @@ export function remultExpress(options) {
|
|
|
24
23
|
httpServerEvents.openHttpServerStream(req, res);
|
|
25
24
|
});
|
|
26
25
|
app.post(streamPath, (r, res, next) => server.withRemult(r, res, next), (req, res) => {
|
|
27
|
-
|
|
26
|
+
server.liveQueryManager.unsubscribe(req.body);
|
|
27
|
+
res.json("ok");
|
|
28
|
+
//httpServerEvents.subscribeToChannel(remult, req.body, res)
|
|
28
29
|
});
|
|
29
30
|
app.get(streamPath + '/stats', (req, res) => {
|
|
30
31
|
httpServerEvents.consoleInfo();
|
|
@@ -50,7 +51,7 @@ export class ServerEventsController {
|
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
53
|
consoleInfo() {
|
|
53
|
-
console.
|
|
54
|
+
console.info(this.connections.map(x => ({
|
|
54
55
|
client: x.clientId,
|
|
55
56
|
channels: x.channels
|
|
56
57
|
})));
|
|
@@ -111,7 +112,6 @@ export class ServerEventsController {
|
|
|
111
112
|
z.messages.push({ id, message: message, eventType });
|
|
112
113
|
while (z.messages.length > z.messageHistoryLength)
|
|
113
114
|
z.messages.shift();
|
|
114
|
-
//console.log({ sendingTo: z.connections.length })
|
|
115
115
|
z.connections.forEach(y => y.write(id, message, eventType));
|
|
116
116
|
}
|
|
117
117
|
}
|
|
@@ -121,12 +121,10 @@ class clientConnection {
|
|
|
121
121
|
this.clientId = clientId;
|
|
122
122
|
this.channels = {};
|
|
123
123
|
this.closed = false;
|
|
124
|
-
//console.log("open connection");
|
|
125
124
|
response.write("event:authenticate\ndata:" + "key" + "\n\n");
|
|
126
125
|
this.sendLiveMessage();
|
|
127
126
|
}
|
|
128
127
|
close() {
|
|
129
|
-
//console.log("close connection");
|
|
130
128
|
this.closed = true;
|
|
131
129
|
}
|
|
132
130
|
write(id, message, eventType) {
|
package/esm/remult-knex/index.js
CHANGED
|
@@ -256,7 +256,7 @@ export class KnexSchemaBuilder {
|
|
|
256
256
|
this.additionalWhere = '';
|
|
257
257
|
}
|
|
258
258
|
async verifyStructureOfAllEntities(remult) {
|
|
259
|
-
console.
|
|
259
|
+
console.info("start verify structure");
|
|
260
260
|
for (const entity of allEntities) {
|
|
261
261
|
let metadata = remult.repo(entity).metadata;
|
|
262
262
|
try {
|
|
@@ -319,7 +319,7 @@ export class KnexSchemaBuilder {
|
|
|
319
319
|
}
|
|
320
320
|
}
|
|
321
321
|
catch (err) {
|
|
322
|
-
console.
|
|
322
|
+
console.error(err);
|
|
323
323
|
}
|
|
324
324
|
}
|
|
325
325
|
}
|
|
@@ -5,7 +5,7 @@ import { AllowedForInstance, Remult, UserInfo } from '../src/context';
|
|
|
5
5
|
import { ClassType } from '../classType';
|
|
6
6
|
import { Repository } from '../src/remult3';
|
|
7
7
|
import { IdEntity } from '../src/id-entity';
|
|
8
|
-
import { LiveQueryPublisher } from '../src/live-query/
|
|
8
|
+
import { LiveQueryPublisher } from '../src/live-query/LiveQueryPublisher';
|
|
9
9
|
export interface RemultServerOptions<RequestType extends GenericRequest> {
|
|
10
10
|
/** Sets a database connection for Remult.
|
|
11
11
|
*
|
|
@@ -162,7 +162,7 @@ export class RemultServerImplementation {
|
|
|
162
162
|
add(key, dataApiFactory, r) {
|
|
163
163
|
let myRoute = this.options.rootPath + '/' + key;
|
|
164
164
|
if (this.options.logApiEndPoints)
|
|
165
|
-
console.
|
|
165
|
+
console.info("[remult] " + myRoute);
|
|
166
166
|
r.route(myRoute)
|
|
167
167
|
.get(this.process((c, req, res) => dataApiFactory(c).httpGet(res, req))).put(this.process(async (c, req, res, orig) => dataApiFactory(c).put(res, '', orig.body)))
|
|
168
168
|
.delete(this.process(async (c, req, res, orig) => dataApiFactory(c).delete(res, '')))
|
|
@@ -225,7 +225,7 @@ export class RemultServerImplementation {
|
|
|
225
225
|
})();
|
|
226
226
|
this.backendMethodsOpenApi.push({ path: myUrl, allowed, tag });
|
|
227
227
|
if (this.options.logApiEndPoints)
|
|
228
|
-
console.
|
|
228
|
+
console.info("[remult] " + myUrl);
|
|
229
229
|
if (queue) {
|
|
230
230
|
this.hasQueue = true;
|
|
231
231
|
this.queue.mapQueuedAction(myUrl, what);
|
package/esm/src/context.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { DataProvider, RestDataProviderHttpProvider } from "./data-interfaces";
|
|
|
2
2
|
import { RestDataProviderHttpProviderUsingFetch } from './data-providers/rest-data-provider';
|
|
3
3
|
import { EntityMetadata, EntityRef, FindOptions, Repository } from "./remult3";
|
|
4
4
|
import { ClassType } from "../classType";
|
|
5
|
-
import { LiveQueryClient } from "./live-query/
|
|
5
|
+
import { LiveQueryClient } from "./live-query/LiveQuerySubscriber";
|
|
6
6
|
export interface ExternalHttpProvider {
|
|
7
7
|
post(url: string, data: any): Promise<any> | {
|
|
8
8
|
toPromise(): Promise<any>;
|
package/esm/src/context.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { actionInfo, serverActionField } from './server-action';
|
|
2
2
|
import { RestDataProvider, RestDataProviderHttpProviderUsingFetch } from './data-providers/rest-data-provider';
|
|
3
3
|
import { RepositoryImplementation } from "./remult3/RepositoryImplementation";
|
|
4
|
-
import { LiveQueryClient } from "./live-query/
|
|
4
|
+
import { LiveQueryClient } from "./live-query/LiveQuerySubscriber";
|
|
5
5
|
import { EventSourceLiveQueryProvider } from "./live-query/EventSourceLiveQueryProvider";
|
|
6
6
|
import { RemultProxy } from "./remult-proxy";
|
|
7
7
|
export class HttpProviderBridgeToRestDataProviderHttpProvider {
|
package/esm/src/data-api.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { customUrlToken, buildFilterFromRequestParameters } from './filter/filter-interfaces';
|
|
2
2
|
import { Filter } from './filter/filter-interfaces';
|
|
3
|
+
import { ForbiddenError } from './server-action';
|
|
3
4
|
export class DataApi {
|
|
4
5
|
constructor(repository, remult, liveQueryProvider) {
|
|
5
6
|
this.repository = repository;
|
|
@@ -175,17 +176,26 @@ export class DataApi {
|
|
|
175
176
|
}
|
|
176
177
|
async post(response, body) {
|
|
177
178
|
try {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
179
|
+
const insert = async (what) => {
|
|
180
|
+
let newr = this.repository.create();
|
|
181
|
+
await this.repository.getEntityRef(newr)._updateEntityBasedOnApi(what);
|
|
182
|
+
if (!this.repository.getEntityRef(newr).apiInsertAllowed) {
|
|
183
|
+
throw new ForbiddenError();
|
|
184
|
+
}
|
|
185
|
+
await this.repository.getEntityRef(newr).save();
|
|
186
|
+
return this.repository.getEntityRef(newr).toApiJson();
|
|
187
|
+
};
|
|
188
|
+
if (Array.isArray(body)) {
|
|
189
|
+
response.created(await Promise.all(body.map(x => insert(x))));
|
|
183
190
|
}
|
|
184
|
-
|
|
185
|
-
|
|
191
|
+
else
|
|
192
|
+
response.created(await insert(body));
|
|
186
193
|
}
|
|
187
194
|
catch (err) {
|
|
188
|
-
|
|
195
|
+
if (err.isForbiddenError)
|
|
196
|
+
response.forbidden();
|
|
197
|
+
else
|
|
198
|
+
response.error(err);
|
|
189
199
|
}
|
|
190
200
|
}
|
|
191
201
|
}
|
|
@@ -76,7 +76,7 @@ class LogSQLCommand {
|
|
|
76
76
|
if (this.allQueries) {
|
|
77
77
|
var d = new Date().valueOf() - start.valueOf();
|
|
78
78
|
if (d > SqlDatabase.durationThreshold) {
|
|
79
|
-
console.
|
|
79
|
+
console.info({ query: sql, arguments: this.args, duration: d / 1000 });
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
return r;
|
|
@@ -18,7 +18,7 @@ export class WebSqlDataProvider {
|
|
|
18
18
|
let e = await getDbNameProvider(entity);
|
|
19
19
|
let sql = 'drop table if exists ' + e.entityName;
|
|
20
20
|
if (SqlDatabase.LogToConsole)
|
|
21
|
-
console.
|
|
21
|
+
console.info(sql);
|
|
22
22
|
await this.createCommand().execute(sql);
|
|
23
23
|
}
|
|
24
24
|
async createTable(entity) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { LiveQueryProvider, MessageHandler } from "./
|
|
1
|
+
import { LiveQueryProvider, MessageHandler } from "./LiveQuerySubscriber";
|
|
2
2
|
export declare class EventSourceLiveQueryProvider implements LiveQueryProvider {
|
|
3
3
|
private wrapMessage?;
|
|
4
4
|
constructor(wrapMessage?: (what: () => void) => void);
|
|
5
|
-
openStreamAndReturnCloseFunction(clientId: string, onMessage: MessageHandler): Promise<VoidFunction>;
|
|
5
|
+
openStreamAndReturnCloseFunction(clientId: string, onMessage: MessageHandler, onReconnect: VoidFunction): Promise<VoidFunction>;
|
|
6
6
|
}
|
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
import { remult } from "../remult-proxy";
|
|
2
|
-
import { streamUrl } from "./
|
|
2
|
+
import { streamUrl } from "./LiveQuerySubscriber";
|
|
3
3
|
export class EventSourceLiveQueryProvider {
|
|
4
4
|
constructor(wrapMessage) {
|
|
5
5
|
this.wrapMessage = wrapMessage;
|
|
6
6
|
if (!this.wrapMessage)
|
|
7
7
|
this.wrapMessage = x => x();
|
|
8
8
|
}
|
|
9
|
-
openStreamAndReturnCloseFunction(clientId, onMessage) {
|
|
9
|
+
openStreamAndReturnCloseFunction(clientId, onMessage, onReconnect) {
|
|
10
10
|
const source = new EventSource(remult.apiClient.url + '/' + streamUrl + "?id=" + clientId, {
|
|
11
11
|
withCredentials: true
|
|
12
12
|
});
|
|
13
13
|
source.onmessage = e => {
|
|
14
14
|
this.wrapMessage(() => onMessage(JSON.parse(e.data)));
|
|
15
15
|
};
|
|
16
|
+
source.onerror = e => {
|
|
17
|
+
console.error("Live Query Event Source Error", e);
|
|
18
|
+
};
|
|
16
19
|
return new Promise((res) => {
|
|
20
|
+
let connected = false;
|
|
17
21
|
source.onopen = e => {
|
|
22
|
+
if (connected)
|
|
23
|
+
onReconnect();
|
|
24
|
+
connected = true;
|
|
18
25
|
res(() => {
|
|
19
26
|
source.close();
|
|
20
27
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EntityOrderBy, FindOptions, Remult, Repository, RestDataProviderHttpProvider } from '../../index';
|
|
2
2
|
import { Allowed } from '../context';
|
|
3
|
-
import { ServerEventDispatcher } from './
|
|
3
|
+
import { ServerEventDispatcher } from './LiveQueryPublisher';
|
|
4
4
|
export declare const streamUrl = "stream1";
|
|
5
5
|
export interface LiveQueryProvider {
|
|
6
6
|
openStreamAndReturnCloseFunction(clientId: string, onMessage: MessageHandler): Promise<VoidFunction>;
|
|
@@ -4,7 +4,7 @@ import { RestEntityDataProvider } from '../data-providers/rest-data-provider';
|
|
|
4
4
|
import { buildRestDataProvider } from '../context';
|
|
5
5
|
import { getId } from '../remult3/getId';
|
|
6
6
|
export const streamUrl = 'stream1';
|
|
7
|
-
class
|
|
7
|
+
class LiveQuerySubscriber {
|
|
8
8
|
constructor(repo, query) {
|
|
9
9
|
this.repo = repo;
|
|
10
10
|
this.query = query;
|
|
@@ -54,6 +54,7 @@ class LiveQueryOnFrontEnd {
|
|
|
54
54
|
this.forListeners(listener => listener(items => {
|
|
55
55
|
if (!items)
|
|
56
56
|
items = [];
|
|
57
|
+
items = items.filter(x => getId(this.repo.metadata, x) !== getId(this.repo.metadata, item));
|
|
57
58
|
items.push(item);
|
|
58
59
|
return sort(items);
|
|
59
60
|
}));
|
|
@@ -141,7 +142,7 @@ export class LiveQueryClient {
|
|
|
141
142
|
const eventTypeKey = JSON.stringify({ url, filterObject });
|
|
142
143
|
let q = this.queries.get(eventTypeKey);
|
|
143
144
|
if (!q) {
|
|
144
|
-
this.queries.set(eventTypeKey, q = new
|
|
145
|
+
this.queries.set(eventTypeKey, q = new LiveQuerySubscriber(repo, { entityKey: repo.metadata.key, orderBy: options.orderBy }));
|
|
145
146
|
url.add("__action", 'subscribe|' + this.clientId);
|
|
146
147
|
const thenResult = (r) => {
|
|
147
148
|
this.runPromise(q.setAllItems(r.result));
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Remult } from '../..';
|
|
2
|
+
import { Repository, EntityRef, FindOptions } from '../remult3';
|
|
3
|
+
import { LiveQueryProvider } from '../data-api';
|
|
4
|
+
import { ChannelSubscribe, liveQueryMessage } from './LiveQuerySubscriber';
|
|
5
|
+
export declare class LiveQueryPublisher implements LiveQueryProvider {
|
|
6
|
+
private dispatcher;
|
|
7
|
+
unsubscribe(data: ChannelSubscribe): void;
|
|
8
|
+
constructor(dispatcher: ServerEventDispatcher);
|
|
9
|
+
subscribe(repo: Repository<any>, clientId: string, findOptions: FindOptions<any>, remult: Remult, ids: any[]): string;
|
|
10
|
+
clients: clientInfo[];
|
|
11
|
+
hasListeners(ref: EntityRef<any>): boolean;
|
|
12
|
+
runPromise(p: Promise<any>): void;
|
|
13
|
+
saved(ref: EntityRef<any>): void;
|
|
14
|
+
deleted(ref: EntityRef<any>): void;
|
|
15
|
+
}
|
|
16
|
+
export interface clientInfo {
|
|
17
|
+
clientId: string;
|
|
18
|
+
queries: ({
|
|
19
|
+
id: string;
|
|
20
|
+
repo: Repository<any>;
|
|
21
|
+
findOptions: FindOptions<any>;
|
|
22
|
+
ids: any[];
|
|
23
|
+
})[];
|
|
24
|
+
}
|
|
25
|
+
export interface ServerEventDispatcher {
|
|
26
|
+
sendQueryMessage(message: ServerEventMessage): void;
|
|
27
|
+
sendChannelMessage<T>(channel: string, message: any): void;
|
|
28
|
+
}
|
|
29
|
+
export interface ServerEventMessage {
|
|
30
|
+
clientId: string;
|
|
31
|
+
queryId: string;
|
|
32
|
+
message: liveQueryMessage;
|
|
33
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { v4 as uuid } from 'uuid';
|
|
2
|
+
export class LiveQueryPublisher {
|
|
3
|
+
constructor(dispatcher) {
|
|
4
|
+
this.dispatcher = dispatcher;
|
|
5
|
+
this.clients = [];
|
|
6
|
+
}
|
|
7
|
+
unsubscribe(data) {
|
|
8
|
+
let client = this.clients.find(c => c.clientId === data.clientId);
|
|
9
|
+
if (client)
|
|
10
|
+
client.queries = client.queries.filter(q => q.id !== data.channel);
|
|
11
|
+
}
|
|
12
|
+
subscribe(repo, clientId, findOptions, remult, ids) {
|
|
13
|
+
let client = this.clients.find(c => c.clientId === clientId);
|
|
14
|
+
if (!client) {
|
|
15
|
+
this.clients.push(client = { clientId: clientId, queries: [] });
|
|
16
|
+
}
|
|
17
|
+
const id = uuid();
|
|
18
|
+
client.queries.push({
|
|
19
|
+
id,
|
|
20
|
+
findOptions: findOptions,
|
|
21
|
+
repo,
|
|
22
|
+
ids
|
|
23
|
+
});
|
|
24
|
+
return id;
|
|
25
|
+
}
|
|
26
|
+
hasListeners(ref) {
|
|
27
|
+
for (const c of this.clients) {
|
|
28
|
+
for (const q of c.queries) {
|
|
29
|
+
if (q.repo.metadata.key === ref.metadata.key)
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
runPromise(p) {
|
|
36
|
+
}
|
|
37
|
+
//TODO - reconsider usage of zone
|
|
38
|
+
saved(ref) {
|
|
39
|
+
const isNew = ref.isNew();
|
|
40
|
+
const origId = isNew ? ref.getId() : ref.getOriginalId();
|
|
41
|
+
for (const c of this.clients) {
|
|
42
|
+
for (const q of c.queries) {
|
|
43
|
+
if (q.repo.metadata.key === ref.metadata.key) {
|
|
44
|
+
this.runPromise(q.repo.find(q.findOptions).then(currentItems => {
|
|
45
|
+
const currentIds = currentItems.map(x => q.repo.getEntityRef(x).getId());
|
|
46
|
+
const sendMessage = (message) => {
|
|
47
|
+
this.dispatcher.sendQueryMessage({ clientId: c.clientId, queryId: q.id, message });
|
|
48
|
+
};
|
|
49
|
+
for (const id of q.ids.filter(y => !currentIds.includes(y))) {
|
|
50
|
+
if (id != origId || !currentIds.includes(ref.getId()))
|
|
51
|
+
sendMessage({
|
|
52
|
+
type: "remove",
|
|
53
|
+
data: {
|
|
54
|
+
id: id
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
for (const item of currentItems) {
|
|
59
|
+
const itemRef = q.repo.getEntityRef(item);
|
|
60
|
+
if (itemRef.getId() == ref.getId() && q.ids.includes(origId)) {
|
|
61
|
+
sendMessage({
|
|
62
|
+
type: "replace",
|
|
63
|
+
data: {
|
|
64
|
+
oldId: origId,
|
|
65
|
+
item: itemRef.toApiJson()
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
else if (!q.ids.includes(itemRef.getId())) {
|
|
70
|
+
sendMessage({
|
|
71
|
+
type: "add",
|
|
72
|
+
data: { item: itemRef.toApiJson() }
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
q.ids = currentIds;
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
deleted(ref) {
|
|
83
|
+
const id = ref.getOriginalId();
|
|
84
|
+
for (const c of this.clients) {
|
|
85
|
+
for (const q of c.queries) {
|
|
86
|
+
if (q.repo.metadata.key === ref.metadata.key) {
|
|
87
|
+
if (q.ids.includes(id)) {
|
|
88
|
+
this.dispatcher.sendQueryMessage({
|
|
89
|
+
clientId: c.clientId, queryId: q.id, message: {
|
|
90
|
+
type: "remove",
|
|
91
|
+
data: {
|
|
92
|
+
id: id
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
q.ids = q.ids.filter(y => y != id);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { EntityOrderBy, FindOptions, Remult, Repository, RestDataProviderHttpProvider } from '../../index';
|
|
2
|
+
import { Allowed } from '../context';
|
|
3
|
+
import { ServerEventDispatcher } from './LiveQueryPublisher';
|
|
4
|
+
export declare const streamUrl = "stream1";
|
|
5
|
+
export interface LiveQueryProvider {
|
|
6
|
+
openStreamAndReturnCloseFunction(clientId: string, onMessage: MessageHandler, onReconnect: VoidFunction): Promise<VoidFunction>;
|
|
7
|
+
}
|
|
8
|
+
export declare type MessageHandler = (message: {
|
|
9
|
+
data: any;
|
|
10
|
+
event: string;
|
|
11
|
+
}) => void;
|
|
12
|
+
export declare class LiveQueryClient {
|
|
13
|
+
lqp: LiveQueryProvider;
|
|
14
|
+
private provider?;
|
|
15
|
+
clientId: any;
|
|
16
|
+
private queries;
|
|
17
|
+
private channels;
|
|
18
|
+
constructor(lqp: LiveQueryProvider, provider?: RestDataProviderHttpProvider);
|
|
19
|
+
runPromise(p: Promise<any>): Promise<any>;
|
|
20
|
+
close(): void;
|
|
21
|
+
subscribeChannel<T>(key: string, onResult: (item: T) => void): () => void;
|
|
22
|
+
private closeIfNoListeners;
|
|
23
|
+
subscribe<entityType>(repo: Repository<entityType>, options: FindOptions<entityType>, onResult: (reducer: (prevState: entityType[]) => entityType[]) => void): () => void;
|
|
24
|
+
closeListener: Promise<VoidFunction>;
|
|
25
|
+
private openIfNoOpened;
|
|
26
|
+
}
|
|
27
|
+
export declare type listener = (message: any) => void;
|
|
28
|
+
export interface SubscribeToQueryArgs<entityType = any> {
|
|
29
|
+
entityKey: string;
|
|
30
|
+
orderBy?: EntityOrderBy<entityType>;
|
|
31
|
+
}
|
|
32
|
+
export declare type liveQueryMessage = {
|
|
33
|
+
type: "all";
|
|
34
|
+
data: any[];
|
|
35
|
+
} | {
|
|
36
|
+
type: "add";
|
|
37
|
+
data: any;
|
|
38
|
+
} | {
|
|
39
|
+
type: 'replace';
|
|
40
|
+
data: {
|
|
41
|
+
oldId: any;
|
|
42
|
+
item: any;
|
|
43
|
+
};
|
|
44
|
+
} | {
|
|
45
|
+
type: "remove";
|
|
46
|
+
data: {
|
|
47
|
+
id: any;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
export interface SubscribeResult {
|
|
51
|
+
result: [];
|
|
52
|
+
id: string;
|
|
53
|
+
}
|
|
54
|
+
export interface ChannelSubscribe {
|
|
55
|
+
clientId: string;
|
|
56
|
+
channel: string;
|
|
57
|
+
remove: boolean;
|
|
58
|
+
}
|
|
59
|
+
export declare class AMessageChannel<messageType> {
|
|
60
|
+
private subscribedAllowed;
|
|
61
|
+
userCanSubscribe(channel: string, remult: Remult): boolean;
|
|
62
|
+
private key;
|
|
63
|
+
constructor(key: (string | ((remult: Remult) => string)), subscribedAllowed: Allowed);
|
|
64
|
+
send(what: messageType, remult?: Remult): void;
|
|
65
|
+
subscribe(client: LiveQueryClient, onValue: (value: messageType) => void, remult?: Remult): void;
|
|
66
|
+
dispatcher: ServerEventDispatcher;
|
|
67
|
+
}
|