prostgles-server 4.2.639 → 4.2.641
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/debug/diff-review-build.log +4 -0
- package/debug/diff-review-test-server.log +551 -0
- package/debug/diff-review-tests-build.log +0 -0
- package/debug/nested-aggregate-build.log +4 -0
- package/debug/nested-aggregate-test-compile.log +0 -0
- package/debug/nested-aggregate-test-server.log +586 -0
- package/debug/sort-query-build.log +4 -0
- package/debug/sort-query-tests-build.log +0 -0
- package/debug/sync-logging-build.log +4 -0
- package/debug/sync-logging-main.log +688 -0
- package/debug/sync-logging-server-build.log +0 -0
- package/debug/sync-race-client-build.log +12 -0
- package/debug/sync-race-main-e2e-final.log +659 -0
- package/debug/sync-race-main-e2e.log +643 -0
- package/debug/sync-race-server-build.log +11 -0
- package/debug/sync-race-test-lib-final.log +59 -0
- package/debug/sync-race-test-lib.log +59 -0
- package/debug/sync-review-build.log +4 -0
- package/debug/sync-review-client-build.log +0 -0
- package/debug/sync-review-main-final.log +685 -0
- package/debug/sync-review-main.log +644 -0
- package/debug/sync-review-server-build.log +0 -0
- package/debug/sync-review-syncData.js +147 -0
- package/debug/sync-review-without-reconcile.log +647 -0
- package/dist/Auth/AuthHandler.d.ts +2 -2
- package/dist/Auth/AuthHandler.d.ts.map +1 -1
- package/dist/Auth/AuthHandler.js.map +1 -1
- package/dist/Auth/AuthTypes.d.ts +2 -2
- package/dist/Auth/AuthTypes.d.ts.map +1 -1
- package/dist/Auth/utils/getClientRequestIPsInfo.d.ts +2 -2
- package/dist/Auth/utils/getClientRequestIPsInfo.d.ts.map +1 -1
- package/dist/DBEventsManager.d.ts +5 -5
- package/dist/DBEventsManager.d.ts.map +1 -1
- package/dist/DBEventsManager.js.map +1 -1
- package/dist/DboBuilder/DboBuilderTypes.d.ts +1 -1
- package/dist/DboBuilder/DboBuilderTypes.d.ts.map +1 -1
- package/dist/DboBuilder/QueryBuilder/getJoinQuery.d.ts.map +1 -1
- package/dist/DboBuilder/QueryBuilder/getJoinQuery.js +4 -3
- package/dist/DboBuilder/QueryBuilder/getJoinQuery.js.map +1 -1
- package/dist/DboBuilder/dboBuilderUtils.d.ts +1 -1
- package/dist/DboBuilder/dboBuilderUtils.d.ts.map +1 -1
- package/dist/DboBuilder/dboBuilderUtils.js +3 -2
- package/dist/DboBuilder/dboBuilderUtils.js.map +1 -1
- package/dist/DboBuilder/runSql/QueryStreamer.d.ts +2 -2
- package/dist/DboBuilder/runSql/QueryStreamer.d.ts.map +1 -1
- package/dist/Logging.d.ts +4 -0
- package/dist/Logging.d.ts.map +1 -1
- package/dist/Prostgles.d.ts +4 -4
- package/dist/Prostgles.d.ts.map +1 -1
- package/dist/Prostgles.js.map +1 -1
- package/dist/ProstglesTypes.d.ts +3 -3
- package/dist/ProstglesTypes.d.ts.map +1 -1
- package/dist/PubSubManager/PubSubManager.d.ts +8 -7
- package/dist/PubSubManager/PubSubManager.d.ts.map +1 -1
- package/dist/PubSubManager/PubSubManager.js.map +1 -1
- package/dist/PubSubManager/SyncReplication/getSyncUtilFunctions.d.ts +2 -2
- package/dist/PubSubManager/SyncReplication/getSyncUtilFunctions.d.ts.map +1 -1
- package/dist/PubSubManager/SyncReplication/getSyncUtilFunctions.js +1 -3
- package/dist/PubSubManager/SyncReplication/getSyncUtilFunctions.js.map +1 -1
- package/dist/PubSubManager/SyncReplication/logSyncError.d.ts +6 -0
- package/dist/PubSubManager/SyncReplication/logSyncError.d.ts.map +1 -0
- package/dist/PubSubManager/SyncReplication/logSyncError.js +18 -0
- package/dist/PubSubManager/SyncReplication/logSyncError.js.map +1 -0
- package/dist/PubSubManager/SyncReplication/syncData.d.ts.map +1 -1
- package/dist/PubSubManager/SyncReplication/syncData.js +48 -27
- package/dist/PubSubManager/SyncReplication/syncData.js.map +1 -1
- package/dist/PubSubManager/addSync.d.ts.map +1 -1
- package/dist/PubSubManager/addSync.js +3 -3
- package/dist/PubSubManager/addSync.js.map +1 -1
- package/dist/PubSubManager/addTrigger.d.ts +2 -2
- package/dist/PubSubManager/addTrigger.d.ts.map +1 -1
- package/dist/PubSubManager/addTrigger.js.map +1 -1
- package/dist/WebsocketAPI/onSocketConnected.d.ts +2 -2
- package/dist/WebsocketAPI/onSocketConnected.d.ts.map +1 -1
- package/dist/WebsocketAPI/onSocketConnected.js.map +1 -1
- package/dist/WebsocketAPI/pushSocketSchema.d.ts +2 -2
- package/dist/WebsocketAPI/pushSocketSchema.d.ts.map +1 -1
- package/dist/WebsocketAPI/pushSocketSchema.js.map +1 -1
- package/lib/Auth/AuthHandler.ts +2 -2
- package/lib/Auth/AuthTypes.ts +2 -2
- package/lib/Auth/utils/getClientRequestIPsInfo.ts +2 -2
- package/lib/DBEventsManager.ts +5 -5
- package/lib/DboBuilder/DboBuilderTypes.ts +1 -1
- package/lib/DboBuilder/QueryBuilder/getJoinQuery.ts +5 -4
- package/lib/DboBuilder/dboBuilderUtils.ts +7 -2
- package/lib/DboBuilder/runSql/QueryStreamer.ts +2 -2
- package/lib/Logging.ts +5 -0
- package/lib/Prostgles.ts +2 -2
- package/lib/ProstglesTypes.ts +3 -3
- package/lib/PubSubManager/PubSubManager.ts +7 -6
- package/lib/PubSubManager/SyncReplication/getSyncUtilFunctions.ts +3 -8
- package/lib/PubSubManager/SyncReplication/logSyncError.ts +22 -0
- package/lib/PubSubManager/SyncReplication/syncData.ts +54 -30
- package/lib/PubSubManager/addSync.ts +3 -4
- package/lib/PubSubManager/addTrigger.ts +2 -2
- package/lib/WebsocketAPI/onSocketConnected.ts +2 -2
- package/lib/WebsocketAPI/pushSocketSchema.ts +2 -2
- package/package.json +1 -1
package/lib/Auth/AuthHandler.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AnyObject } from "prostgles-types";
|
|
2
2
|
import { CHANNELS, getProperty, isDefined } from "prostgles-types";
|
|
3
|
-
import type {
|
|
3
|
+
import type { ClientSocketWithCachedData } from "../DboBuilder/DboBuilder";
|
|
4
4
|
import type { DBOFullyTyped } from "../DBSchemaBuilder/DBSchemaBuilder";
|
|
5
5
|
import type { Prostgles } from "../Prostgles";
|
|
6
6
|
import type { AuthClientRequest, AuthConfig, BasicSession } from "./AuthTypes";
|
|
@@ -226,7 +226,7 @@ export class AuthHandler {
|
|
|
226
226
|
getSidAndUserFromRequest = getSidAndUserFromRequest.bind(this);
|
|
227
227
|
|
|
228
228
|
isNonExpiredSocketSession = (
|
|
229
|
-
socket:
|
|
229
|
+
socket: ClientSocketWithCachedData,
|
|
230
230
|
session: BasicSession | undefined,
|
|
231
231
|
): boolean => {
|
|
232
232
|
const hasExpired = Boolean(session && session.expires <= Date.now());
|
package/lib/Auth/AuthTypes.ts
CHANGED
|
@@ -24,7 +24,7 @@ import type {
|
|
|
24
24
|
UserLike,
|
|
25
25
|
} from "prostgles-types";
|
|
26
26
|
import type { DBOFullyTyped } from "../DBSchemaBuilder/DBSchemaBuilder";
|
|
27
|
-
import type {
|
|
27
|
+
import type { ClientSocketWithCachedData } from "../DboBuilder/DboBuilderTypes";
|
|
28
28
|
import { type CachedSession } from "../DboBuilder/DboBuilderTypes";
|
|
29
29
|
import type { DB } from "../Prostgles";
|
|
30
30
|
import { GET_AUTH_ROUTE } from "./AuthHandler";
|
|
@@ -52,7 +52,7 @@ export type BasicSession = {
|
|
|
52
52
|
onExpiration: "redirect" | "show_error";
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
-
type SocketClientRequest = { socket:
|
|
55
|
+
type SocketClientRequest = { socket: ClientSocketWithCachedData; httpReq?: undefined };
|
|
56
56
|
type HttpClientRequest = {
|
|
57
57
|
httpReq: ExpressReq;
|
|
58
58
|
res: ExpressRes;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ClientSocketWithCachedData } from "../../DboBuilder/DboBuilderTypes";
|
|
2
2
|
import type { ExpressReq, LoginClientInfo } from "../AuthTypes";
|
|
3
3
|
type ClientReq =
|
|
4
|
-
| { socket:
|
|
4
|
+
| { socket: ClientSocketWithCachedData; httpReq?: undefined }
|
|
5
5
|
| { httpReq: ExpressReq; socket?: undefined };
|
|
6
6
|
export const getClientRequestIPsInfo = <T extends ClientReq>(req: T): LoginClientInfo => {
|
|
7
7
|
if (req.httpReq) {
|
package/lib/DBEventsManager.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { PrglNotifListener } from "./PostgresNotifListenManager";
|
|
|
2
2
|
import { PostgresNotifListenManager } from "./PostgresNotifListenManager";
|
|
3
3
|
import type { DB, PGP } from "./Prostgles";
|
|
4
4
|
import { getKeys, CHANNELS } from "prostgles-types";
|
|
5
|
-
import type {
|
|
5
|
+
import type { ClientSocketWithCachedData } from "./DboBuilder/DboBuilder";
|
|
6
6
|
|
|
7
7
|
export class DBEventsManager {
|
|
8
8
|
notifies: {
|
|
@@ -65,7 +65,7 @@ export class DBEventsManager {
|
|
|
65
65
|
|
|
66
66
|
async addNotify(
|
|
67
67
|
query: string,
|
|
68
|
-
socket?:
|
|
68
|
+
socket?: ClientSocketWithCachedData,
|
|
69
69
|
func?: any
|
|
70
70
|
): Promise<{
|
|
71
71
|
socketChannel: string;
|
|
@@ -142,7 +142,7 @@ export class DBEventsManager {
|
|
|
142
142
|
};
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
removeNotify(channel?: string, socket?:
|
|
145
|
+
removeNotify(channel?: string, socket?: ClientSocketWithCachedData, func?: any) {
|
|
146
146
|
const notifChannel = channel && this.notifies[channel];
|
|
147
147
|
if (notifChannel) {
|
|
148
148
|
if (socket) {
|
|
@@ -163,7 +163,7 @@ export class DBEventsManager {
|
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
-
addNotice(socket:
|
|
166
|
+
addNotice(socket: ClientSocketWithCachedData) {
|
|
167
167
|
if (!socket.id) throw "Expecting a socket obj with id";
|
|
168
168
|
|
|
169
169
|
if (!this.notice.sockets.find((s) => s.id === socket.id)) {
|
|
@@ -180,7 +180,7 @@ export class DBEventsManager {
|
|
|
180
180
|
return { socketChannel, socketUnsubChannel };
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
-
removeNotice(socket:
|
|
183
|
+
removeNotice(socket: ClientSocketWithCachedData) {
|
|
184
184
|
if (!socket.id) throw "Expecting a socket obj with id";
|
|
185
185
|
this.notice.sockets = this.notice.sockets.filter((s) => s.id !== socket.id);
|
|
186
186
|
}
|
|
@@ -94,7 +94,6 @@ export const getJoinQuery = (viewHandler: ViewHandler, { q1, q2 }: Args): GetJoi
|
|
|
94
94
|
paths.length === 1 ? targetTableAliasRaw : undefined,
|
|
95
95
|
).rawAlias,
|
|
96
96
|
_joinFields: firstJoinTableJoinFields,
|
|
97
|
-
jsonAggSort,
|
|
98
97
|
});
|
|
99
98
|
|
|
100
99
|
const joinType = q2.isLeftJoin ? "LEFT" : "INNER";
|
|
@@ -286,7 +285,6 @@ type GetSelectFieldsArgs = {
|
|
|
286
285
|
q: NewQueryJoin;
|
|
287
286
|
firstJoinTableAlias: string;
|
|
288
287
|
_joinFields: string[];
|
|
289
|
-
jsonAggSort: string;
|
|
290
288
|
};
|
|
291
289
|
|
|
292
290
|
export type SelectItemNested = SelectItemValidated & {
|
|
@@ -297,7 +295,6 @@ const getNestedSelectFields = ({
|
|
|
297
295
|
q,
|
|
298
296
|
firstJoinTableAlias,
|
|
299
297
|
_joinFields,
|
|
300
|
-
jsonAggSort,
|
|
301
298
|
}: GetSelectFieldsArgs) => {
|
|
302
299
|
const targetTableAlias = q.tableAlias || q.table;
|
|
303
300
|
|
|
@@ -325,7 +322,11 @@ const getNestedSelectFields = ({
|
|
|
325
322
|
|
|
326
323
|
const getQuery = (tableAlias?: string) => {
|
|
327
324
|
const partitionBy = `PARTITION BY ${requiredJoinFields.map((f) => asNameAlias(f, tableAlias)).join(", ")}`;
|
|
328
|
-
|
|
325
|
+
// Output aliases are not available inside a window expression in this SELECT.
|
|
326
|
+
const orderBy = prepareOrderByQuery(q.orderByItems, targetTableAlias.raw, (key) =>
|
|
327
|
+
selectedFields.find((field) => field.alias === key)?.getQuery(targetTableAlias.raw),
|
|
328
|
+
).join(", ");
|
|
329
|
+
return `ROW_NUMBER() OVER(${partitionBy} ${orderBy}) AS ${NESTED_ROWID_FIELD_NAME}`;
|
|
329
330
|
};
|
|
330
331
|
|
|
331
332
|
if (q.limit) {
|
|
@@ -148,7 +148,11 @@ export const getConstraints = async (
|
|
|
148
148
|
);
|
|
149
149
|
};
|
|
150
150
|
|
|
151
|
-
export const prepareOrderByQuery = (
|
|
151
|
+
export const prepareOrderByQuery = (
|
|
152
|
+
items: SortItem[],
|
|
153
|
+
tableAlias?: string,
|
|
154
|
+
getExpression?: (key: string) => string | undefined,
|
|
155
|
+
): string[] => {
|
|
152
156
|
if (!items.length) return [];
|
|
153
157
|
return [
|
|
154
158
|
"ORDER BY " +
|
|
@@ -159,7 +163,8 @@ export const prepareOrderByQuery = (items: SortItem[], tableAlias?: string): str
|
|
|
159
163
|
if (d.type === "query" && d.nested) {
|
|
160
164
|
return d.fieldQuery;
|
|
161
165
|
}
|
|
162
|
-
|
|
166
|
+
const expression = getExpression?.(d.key) ?? asNameAlias(d.key, tableAlias);
|
|
167
|
+
return `${expression} ${orderType} ${nullOrder}`;
|
|
163
168
|
})
|
|
164
169
|
.join(", "),
|
|
165
170
|
];
|
|
@@ -6,14 +6,14 @@ import type { BasicCallback } from "../../PubSubManager/PubSubManager";
|
|
|
6
6
|
import type { VoidFunction } from "../../SchemaWatch/SchemaWatch";
|
|
7
7
|
import type { DB } from "../../initProstgles";
|
|
8
8
|
import type { DboBuilder } from "../DboBuilder";
|
|
9
|
-
import type {
|
|
9
|
+
import type { ClientSocketWithCachedData } from "../DboBuilderTypes";
|
|
10
10
|
import { getErrorAsObject, getSerializedClientErrorFromPGError } from "../dboBuilderUtils";
|
|
11
11
|
import { getDetailedFieldInfo } from "./runSqlUtils";
|
|
12
12
|
import { getConnectionDetails } from "./getAdminClient";
|
|
13
13
|
const Cursor = require("pg-cursor") as typeof CursorType;
|
|
14
14
|
|
|
15
15
|
type ClientStreamedRequest = {
|
|
16
|
-
socket:
|
|
16
|
+
socket: ClientSocketWithCachedData;
|
|
17
17
|
query: string;
|
|
18
18
|
options: SQLOptions | undefined;
|
|
19
19
|
persistConnection?: boolean;
|
package/lib/Logging.ts
CHANGED
|
@@ -43,6 +43,11 @@ export namespace EventTypes {
|
|
|
43
43
|
channelName: string;
|
|
44
44
|
syncParams: SyncParams;
|
|
45
45
|
} & (
|
|
46
|
+
| {
|
|
47
|
+
command: "replicationError";
|
|
48
|
+
source: "client" | "trigger" | "WAL";
|
|
49
|
+
error: unknown;
|
|
50
|
+
}
|
|
46
51
|
| {
|
|
47
52
|
command: "syncData";
|
|
48
53
|
source: "client" | "trigger";
|
package/lib/Prostgles.ts
CHANGED
|
@@ -13,7 +13,7 @@ import type { ProstglesInitOptions } from "./ProstglesTypes";
|
|
|
13
13
|
import { RestApi } from "./RestApi";
|
|
14
14
|
import { TableConfigurator } from "./TableConfig/TableConfigurator";
|
|
15
15
|
|
|
16
|
-
import type {
|
|
16
|
+
import type { ClientSocketWithCachedData } from "./DboBuilder/DboBuilder";
|
|
17
17
|
import { DBHandlerServer, DboBuilder } from "./DboBuilder/DboBuilder";
|
|
18
18
|
export { DBHandlerServer };
|
|
19
19
|
export type PGP = pgPromise.IMain<{}, pg.IClient>;
|
|
@@ -401,7 +401,7 @@ export class Prostgles {
|
|
|
401
401
|
|
|
402
402
|
init = initProstgles.bind(this);
|
|
403
403
|
|
|
404
|
-
connectedSockets:
|
|
404
|
+
connectedSockets: ClientSocketWithCachedData[] = [];
|
|
405
405
|
setupSocketIO() {
|
|
406
406
|
this.checkDb();
|
|
407
407
|
|
package/lib/ProstglesTypes.ts
CHANGED
|
@@ -16,7 +16,7 @@ import type { TableConfig } from "./TableConfig/TableConfigTypes";
|
|
|
16
16
|
import type { TableHooks } from "./TableHooks/TableHooks";
|
|
17
17
|
import type { ResolvedAuditConfig, SchemaConfigAudit } from "./Audit/AuditTypes";
|
|
18
18
|
|
|
19
|
-
import type {
|
|
19
|
+
import type { ClientSocketWithCachedData } from "./DboBuilder/DboBuilder";
|
|
20
20
|
|
|
21
21
|
import type e from "express";
|
|
22
22
|
import type pgPromise from "pg-promise";
|
|
@@ -248,14 +248,14 @@ export type ProstglesInitOptions<
|
|
|
248
248
|
* Use for connection verification. Will disconnect socket on any errors
|
|
249
249
|
*/
|
|
250
250
|
onSocketConnect?: (
|
|
251
|
-
args: AuthRequestParams<S, SUser> & { socket:
|
|
251
|
+
args: AuthRequestParams<S, SUser> & { socket: ClientSocketWithCachedData },
|
|
252
252
|
) => void | Promise<void>;
|
|
253
253
|
|
|
254
254
|
/**
|
|
255
255
|
* Called when a socket disconnects
|
|
256
256
|
*/
|
|
257
257
|
onSocketDisconnect?: (
|
|
258
|
-
args: AuthRequestParams<S, SUser> & { socket:
|
|
258
|
+
args: AuthRequestParams<S, SUser> & { socket: ClientSocketWithCachedData },
|
|
259
259
|
) => void | Promise<void>;
|
|
260
260
|
|
|
261
261
|
/**
|
|
@@ -7,7 +7,7 @@ import type {
|
|
|
7
7
|
DBHandlerServer,
|
|
8
8
|
DboBuilder,
|
|
9
9
|
LocalParams,
|
|
10
|
-
|
|
10
|
+
ClientSocketWithCachedData,
|
|
11
11
|
} from "../DboBuilder/DboBuilder";
|
|
12
12
|
import type { PostgresNotifListenManager } from "../PostgresNotifListenManager";
|
|
13
13
|
import type { DB } from "../Prostgles";
|
|
@@ -60,12 +60,13 @@ export type SyncParams = {
|
|
|
60
60
|
throttle?: number;
|
|
61
61
|
lr?: AnyObject;
|
|
62
62
|
is_syncing: boolean;
|
|
63
|
+
syncQueue?: Promise<void>;
|
|
63
64
|
handlers: ReturnType<(typeof ReplicationProtocol)["getServerHandlers"]>;
|
|
64
65
|
localParams: LocalParams;
|
|
65
66
|
};
|
|
66
67
|
|
|
67
68
|
export type AddSyncParams = SyncTableInfo & {
|
|
68
|
-
socket:
|
|
69
|
+
socket: ClientSocketWithCachedData;
|
|
69
70
|
table_info: TableSchema;
|
|
70
71
|
table_rules: ParsedTableRule;
|
|
71
72
|
allow_delete?: boolean;
|
|
@@ -120,7 +121,7 @@ export type SubscriptionParams = {
|
|
|
120
121
|
subscribeOptions: SubscribeOptions;
|
|
121
122
|
|
|
122
123
|
onData?: OnData;
|
|
123
|
-
socket:
|
|
124
|
+
socket: ClientSocketWithCachedData | undefined;
|
|
124
125
|
localParams?: LocalParams;
|
|
125
126
|
|
|
126
127
|
lastPushed: number;
|
|
@@ -196,7 +197,7 @@ export class PubSubManager {
|
|
|
196
197
|
* Updated through refreshTriggers()
|
|
197
198
|
*/
|
|
198
199
|
_triggers: PubSubManagerTriggers = new Map();
|
|
199
|
-
sockets: Map<string,
|
|
200
|
+
sockets: Map<string, ClientSocketWithCachedData> = new Map();
|
|
200
201
|
|
|
201
202
|
subs: Subscription[] = [];
|
|
202
203
|
syncs: SyncParams[] = [];
|
|
@@ -266,7 +267,7 @@ export class PubSubManager {
|
|
|
266
267
|
|
|
267
268
|
removeSubscription = (
|
|
268
269
|
channelName: string,
|
|
269
|
-
subInfo: { type: "local"; onData: OnData } | { type: "ws"; socket:
|
|
270
|
+
subInfo: { type: "local"; onData: OnData } | { type: "ws"; socket: ClientSocketWithCachedData },
|
|
270
271
|
) => {
|
|
271
272
|
const matchingSubIdx = this.subs.findIndex(
|
|
272
273
|
(s) =>
|
|
@@ -364,7 +365,7 @@ export class PubSubManager {
|
|
|
364
365
|
|
|
365
366
|
pushSubData = pushSubData.bind(this);
|
|
366
367
|
|
|
367
|
-
upsertSocket(socket:
|
|
368
|
+
upsertSocket(socket: ClientSocketWithCachedData | undefined) {
|
|
368
369
|
if (socket && !this.sockets.get(socket.id)) {
|
|
369
370
|
this.sockets.set(socket.id, socket);
|
|
370
371
|
socket.on("disconnect", () => {
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
type AnyObject,
|
|
7
7
|
type SyncBatchParams,
|
|
8
8
|
} from "prostgles-types";
|
|
9
|
-
import type { LocalParams,
|
|
9
|
+
import type { LocalParams, ClientSocketWithCachedData } from "../../DboBuilder/DboBuilder";
|
|
10
10
|
import type { TableHandler } from "../../DboBuilder/TableHandler/TableHandler";
|
|
11
11
|
import { getSyncOrderByAndFields } from "./getSyncOrderByAndFields";
|
|
12
12
|
import type { PubSubManager, SyncParams } from "../PubSubManager";
|
|
@@ -21,7 +21,7 @@ import { log } from "../PubSubManagerUtils";
|
|
|
21
21
|
import type { EventTypes } from "../../Logging";
|
|
22
22
|
|
|
23
23
|
type Args = {
|
|
24
|
-
socket:
|
|
24
|
+
socket: ClientSocketWithCachedData;
|
|
25
25
|
tableHandler: TableHandler;
|
|
26
26
|
sync: SyncParams;
|
|
27
27
|
pubSubManager: PubSubManager;
|
|
@@ -389,12 +389,7 @@ export const getSyncUtilFunctions = ({
|
|
|
389
389
|
return;
|
|
390
390
|
}
|
|
391
391
|
if (sync.lr?.[synced_field] && +sync.lr[synced_field] > +lastRow[synced_field]) {
|
|
392
|
-
|
|
393
|
-
{
|
|
394
|
-
syncIssue: "sync.lr[synced_field] is greater than lastRow[synced_field]",
|
|
395
|
-
},
|
|
396
|
-
sync.table_name,
|
|
397
|
-
);
|
|
392
|
+
return;
|
|
398
393
|
}
|
|
399
394
|
sync.lr = lastRow;
|
|
400
395
|
},
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { EventTypes } from "../../Logging";
|
|
2
|
+
import type { PubSubManager, SyncParams } from "../PubSubManager";
|
|
3
|
+
|
|
4
|
+
export const logSyncError = (
|
|
5
|
+
pubSubManager: PubSubManager,
|
|
6
|
+
sync: SyncParams,
|
|
7
|
+
source: Extract<EventTypes.Sync, { command: "replicationError" }>["source"],
|
|
8
|
+
error: unknown,
|
|
9
|
+
) =>
|
|
10
|
+
pubSubManager._log({
|
|
11
|
+
type: "sync",
|
|
12
|
+
command: "replicationError",
|
|
13
|
+
source,
|
|
14
|
+
error,
|
|
15
|
+
tableName: sync.table_name,
|
|
16
|
+
channelName: sync.channel_name,
|
|
17
|
+
socketId: sync.socket_id,
|
|
18
|
+
sid: sync.sid,
|
|
19
|
+
connectedSocketIds: pubSubManager.connectedSocketIds,
|
|
20
|
+
syncParams: sync,
|
|
21
|
+
duration: -1,
|
|
22
|
+
});
|
|
@@ -4,6 +4,7 @@ import { WAL } from "prostgles-types/dist/WAL";
|
|
|
4
4
|
import type { PubSubManager, SyncParams } from "../PubSubManager";
|
|
5
5
|
import { getSyncUtilFunctions } from "./getSyncUtilFunctions";
|
|
6
6
|
import type { EventTypes } from "../../Logging";
|
|
7
|
+
import { logSyncError } from "./logSyncError";
|
|
7
8
|
|
|
8
9
|
export type ClientSyncInfo = Partial<{
|
|
9
10
|
c_fr: AnyObject;
|
|
@@ -45,7 +46,26 @@ export type ClientExpressData = ClientSyncInfo & {
|
|
|
45
46
|
/**
|
|
46
47
|
* Server or client requested data sync
|
|
47
48
|
*/
|
|
48
|
-
export
|
|
49
|
+
export function syncData(
|
|
50
|
+
this: PubSubManager,
|
|
51
|
+
sync: SyncParams,
|
|
52
|
+
clientData: ClientExpressData | undefined,
|
|
53
|
+
source: "trigger" | "client",
|
|
54
|
+
) {
|
|
55
|
+
const run = () =>
|
|
56
|
+
runSyncData.call(this, sync, clientData, source).catch(async (error) => {
|
|
57
|
+
if (this.sockets.get(sync.socket_id)?.connected) {
|
|
58
|
+
await logSyncError(this, sync, source, error);
|
|
59
|
+
}
|
|
60
|
+
throw error;
|
|
61
|
+
});
|
|
62
|
+
const queued = (sync.syncQueue ?? Promise.resolve()).then(run);
|
|
63
|
+
// Report failures to the caller while allowing the next request to run.
|
|
64
|
+
sync.syncQueue = queued.catch(() => undefined);
|
|
65
|
+
return queued;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function runSyncData(
|
|
49
69
|
this: PubSubManager,
|
|
50
70
|
sync: SyncParams,
|
|
51
71
|
clientData: ClientExpressData | undefined,
|
|
@@ -111,8 +131,12 @@ export async function syncData(
|
|
|
111
131
|
sync.is_syncing = true;
|
|
112
132
|
},
|
|
113
133
|
onSend: async (data) => {
|
|
114
|
-
|
|
115
|
-
|
|
134
|
+
try {
|
|
135
|
+
return await upsertData(data, "WAL");
|
|
136
|
+
} catch (error) {
|
|
137
|
+
await logSyncError(this, sync, "WAL", error);
|
|
138
|
+
throw error;
|
|
139
|
+
}
|
|
116
140
|
},
|
|
117
141
|
onSendEnd: (batch, _, error) => {
|
|
118
142
|
if (error === undefined) {
|
|
@@ -164,36 +188,36 @@ export async function syncData(
|
|
|
164
188
|
}
|
|
165
189
|
|
|
166
190
|
sync.is_syncing = true;
|
|
191
|
+
try {
|
|
192
|
+
let from_synced = null;
|
|
193
|
+
|
|
194
|
+
/** Client runs must reconcile the client's snapshot after reattachment. */
|
|
195
|
+
if (sync.lr && !clientData) {
|
|
196
|
+
const { s_lr } = await getServerRowInfo();
|
|
197
|
+
|
|
198
|
+
/* Make sure trigger is not firing on freshly synced data */
|
|
199
|
+
if (!rowsFullyMatch(sync.lr, s_lr)) {
|
|
200
|
+
from_synced = Number(sync.lr[synced_field]);
|
|
201
|
+
await logSyncData("sync.lr");
|
|
202
|
+
} else {
|
|
203
|
+
await logSyncData("rowsFullyMatch");
|
|
204
|
+
}
|
|
205
|
+
} else {
|
|
206
|
+
await logSyncData("getLastSynced(clientData).start");
|
|
207
|
+
from_synced = await getLastSynced(clientData);
|
|
208
|
+
await logSyncData("getLastSynced(clientData).end");
|
|
209
|
+
}
|
|
167
210
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
if (sync.lr) {
|
|
173
|
-
const { s_lr } = await getServerRowInfo();
|
|
174
|
-
|
|
175
|
-
/* Make sure trigger is not firing on freshly synced data */
|
|
176
|
-
if (!rowsFullyMatch(sync.lr, s_lr)) {
|
|
177
|
-
from_synced = Number(sync.lr[synced_field]);
|
|
178
|
-
await logSyncData("sync.lr");
|
|
211
|
+
if (from_synced !== null) {
|
|
212
|
+
await logSyncData("syncBatch.start");
|
|
213
|
+
await syncBatch(from_synced);
|
|
214
|
+
await logSyncData("syncBatch.end");
|
|
179
215
|
} else {
|
|
180
|
-
await logSyncData("
|
|
216
|
+
await logSyncData("nothingToSync");
|
|
181
217
|
}
|
|
182
|
-
} else {
|
|
183
|
-
await logSyncData("getLastSynced(clientData).start");
|
|
184
|
-
from_synced = await getLastSynced(clientData);
|
|
185
|
-
await logSyncData("getLastSynced(clientData).end");
|
|
186
|
-
}
|
|
187
218
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
await logSyncData("syncBatch.end");
|
|
192
|
-
} else {
|
|
193
|
-
await logSyncData("nothingToSync");
|
|
219
|
+
await pushData({ state: "synced" });
|
|
220
|
+
} finally {
|
|
221
|
+
sync.is_syncing = false;
|
|
194
222
|
}
|
|
195
|
-
|
|
196
|
-
await pushData({ state: "synced" });
|
|
197
|
-
|
|
198
|
-
sync.is_syncing = false;
|
|
199
223
|
}
|
|
@@ -40,7 +40,6 @@ export async function addSync(
|
|
|
40
40
|
/* Only a sync per socket per table/condition/select allowed */
|
|
41
41
|
const existing = find(this.syncs, { socket_id: socket.id, channel_name: channelName });
|
|
42
42
|
if (existing) {
|
|
43
|
-
console.warn("addSync: Client tried to create a duplicate sync", existing.channel_name);
|
|
44
43
|
return existing;
|
|
45
44
|
}
|
|
46
45
|
|
|
@@ -112,18 +111,18 @@ export async function addSync(
|
|
|
112
111
|
cb(null, { res: "ok" });
|
|
113
112
|
});
|
|
114
113
|
|
|
114
|
+
this.syncs.push(newSync);
|
|
115
115
|
return newSync;
|
|
116
116
|
};
|
|
117
117
|
|
|
118
|
-
const newSync = upsertSync();
|
|
119
|
-
|
|
120
118
|
await this.addTrigger(
|
|
121
119
|
{ table_name, condition: conditionParsed, tracked_columns: undefined },
|
|
122
120
|
undefined,
|
|
123
121
|
socket,
|
|
124
122
|
);
|
|
125
123
|
|
|
126
|
-
|
|
124
|
+
// Check and register without yielding so concurrent attachments share one sync.
|
|
125
|
+
const newSync = upsertSync();
|
|
127
126
|
return { channelName, newSync };
|
|
128
127
|
});
|
|
129
128
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as crypto from "crypto";
|
|
2
2
|
import { asName, pickKeys, tryCatchV2 } from "prostgles-types";
|
|
3
|
-
import type {
|
|
3
|
+
import type { ClientSocketWithCachedData } from "../DboBuilder/DboBuilderTypes";
|
|
4
4
|
import type { TableHandler } from "../DboBuilder/TableHandler/TableHandler";
|
|
5
5
|
import type { ViewSubscriptionOptions } from "./PubSubManager";
|
|
6
6
|
import { type PubSubManager } from "./PubSubManager";
|
|
@@ -16,7 +16,7 @@ export async function addTrigger(
|
|
|
16
16
|
this: PubSubManager,
|
|
17
17
|
params: AddTriggerParams,
|
|
18
18
|
viewOptions: ViewSubscriptionOptions | undefined,
|
|
19
|
-
socket:
|
|
19
|
+
socket: ClientSocketWithCachedData | undefined,
|
|
20
20
|
) {
|
|
21
21
|
const addedTrigger = await tryCatchV2(async () => {
|
|
22
22
|
const { table_name } = { ...params };
|
|
@@ -2,12 +2,12 @@ import type { AnyObject, SocketFunctionCall } from "prostgles-types";
|
|
|
2
2
|
import { CHANNELS, getSerialisableError, isObject } from "prostgles-types";
|
|
3
3
|
import { getClientRequestIPsInfo } from "../Auth/AuthHandler";
|
|
4
4
|
import type { AuthResultWithSID, SessionUser } from "../Auth/AuthTypes";
|
|
5
|
-
import type {
|
|
5
|
+
import type { ClientSocketWithCachedData } from "../DboBuilder/DboBuilderTypes";
|
|
6
6
|
import type { DBOFullyTyped } from "../DBSchemaBuilder/DBSchemaBuilder";
|
|
7
7
|
import type { Prostgles, TABLE_METHODS } from "../Prostgles";
|
|
8
8
|
import { runClientMethod, runClientRequest } from "../runClientRequest";
|
|
9
9
|
|
|
10
|
-
export async function onSocketConnected(this: Prostgles, socket:
|
|
10
|
+
export async function onSocketConnected(this: Prostgles, socket: ClientSocketWithCachedData) {
|
|
11
11
|
const isDestroyed = () => this.destroyed;
|
|
12
12
|
if (isDestroyed()) {
|
|
13
13
|
console.log("Socket connected to destroyed instance");
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { CHANNELS, getSerialisableError, type SQLRequest } from "prostgles-types";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ClientSocketWithCachedData } from "../DboBuilder/DboBuilderTypes";
|
|
3
3
|
import type { Prostgles } from "../Prostgles";
|
|
4
4
|
import { runClientSqlRequest } from "../runClientRequest";
|
|
5
5
|
import { makeSocketError } from "./onSocketConnected";
|
|
6
|
-
export async function pushSocketSchema(this: Prostgles, socket:
|
|
6
|
+
export async function pushSocketSchema(this: Prostgles, socket: ClientSocketWithCachedData) {
|
|
7
7
|
const isDestroyed = () => this.destroyed;
|
|
8
8
|
if (isDestroyed()) return;
|
|
9
9
|
try {
|