prostgles-server 4.1.142 → 4.1.144
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/dist/DboBuilder/QueryStreamer.d.ts +2 -2
- package/dist/DboBuilder/QueryStreamer.d.ts.map +1 -1
- package/dist/DboBuilder/QueryStreamer.js +48 -54
- package/dist/DboBuilder/QueryStreamer.js.map +1 -1
- package/lib/DboBuilder/QueryStreamer.ts +62 -62
- package/package.json +3 -2
- package/tests/client/package.json +1 -1
- package/tests/client_only_queries.ts +18 -3
- package/tests/server/package-lock.json +5 -3
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as pg from "pg";
|
|
2
|
-
import QueryStreamType from 'pg-query-stream';
|
|
3
2
|
import { SQLOptions, SocketSQLStreamServer } from "prostgles-types";
|
|
4
3
|
import { DB } from "../initProstgles";
|
|
5
4
|
import { DboBuilder } from "./DboBuilder";
|
|
6
5
|
import { PRGLIOSocket } from "./DboBuilderTypes";
|
|
6
|
+
import CursorType from 'pg-cursor';
|
|
7
7
|
type ClientStreamedRequest = {
|
|
8
8
|
socket: PRGLIOSocket;
|
|
9
9
|
query: string;
|
|
@@ -11,7 +11,7 @@ type ClientStreamedRequest = {
|
|
|
11
11
|
persistConnection?: boolean;
|
|
12
12
|
};
|
|
13
13
|
type StreamedQuery = ClientStreamedRequest & {
|
|
14
|
-
|
|
14
|
+
cursor: CursorType | undefined;
|
|
15
15
|
client: pg.Client | undefined;
|
|
16
16
|
onError: ((error: any) => void);
|
|
17
17
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryStreamer.d.ts","sourceRoot":"","sources":["../../lib/DboBuilder/QueryStreamer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,
|
|
1
|
+
{"version":3,"file":"QueryStreamer.d.ts","sourceRoot":"","sources":["../../lib/DboBuilder/QueryStreamer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAAY,UAAU,EAAyB,qBAAqB,EAAsB,MAAM,iBAAiB,CAAC;AAEzH,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGjD,OAAO,UAAU,MAAM,WAAW,CAAA;AAGlC,KAAK,qBAAqB,GAAG;IAC3B,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,UAAU,GAAG,SAAS,CAAC;IAChC,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAA;AACD,KAAK,aAAa,GAAG,qBAAqB,GAAG;IAC3C,MAAM,EAAE,UAAU,GAAG,SAAS,CAAC;IAC/B,MAAM,EAAE,EAAE,CAAC,MAAM,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC,CAAC;CACjC,CAAA;AAiBD,qBAAa,aAAa;IACxB,EAAE,EAAE,EAAE,CAAC;IACP,UAAU,EAAE,UAAU,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAM;IAClE,WAAW,EAAE,EAAE,CAAC,MAAM,CAAC;gBACX,UAAU,EAAE,UAAU;IAelC,aAAa,mBAAoB,GAAG,KAAK,IAAI,8BAA8B,GAAG,YAAY,eAOzF;IAED,YAAY,aAAc,MAAM,UAO/B;IAED,MAAM,UAAiB,qBAAqB,KAAG,QAAQ,qBAAqB,CAAC,CAkK5E;CACF"}
|
|
@@ -5,7 +5,7 @@ const pg = require("pg");
|
|
|
5
5
|
const prostgles_types_1 = require("prostgles-types");
|
|
6
6
|
const dboBuilderUtils_1 = require("./dboBuilderUtils");
|
|
7
7
|
const runSQL_1 = require("./runSQL");
|
|
8
|
-
const
|
|
8
|
+
const Cursor = require('pg-cursor');
|
|
9
9
|
const shortSocketIds = {};
|
|
10
10
|
const getSetShortSocketId = (socketId) => {
|
|
11
11
|
const shortId = socketId.slice(0, 3);
|
|
@@ -66,7 +66,7 @@ class QueryStreamer {
|
|
|
66
66
|
...query,
|
|
67
67
|
id,
|
|
68
68
|
client: undefined,
|
|
69
|
-
|
|
69
|
+
cursor: undefined,
|
|
70
70
|
onError: (rawError) => {
|
|
71
71
|
if (errored)
|
|
72
72
|
return;
|
|
@@ -85,25 +85,18 @@ class QueryStreamer {
|
|
|
85
85
|
if (!socketQuery) {
|
|
86
86
|
throw "socket query not found";
|
|
87
87
|
}
|
|
88
|
-
|
|
89
|
-
let
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
const emit = (type, streamResult) => {
|
|
93
|
-
const ended = type === "ended";
|
|
94
|
-
if (finished)
|
|
95
|
-
return;
|
|
96
|
-
finished = finished || ended;
|
|
97
|
-
if (!streamResult?.fields)
|
|
88
|
+
/** Only send fields on first request */
|
|
89
|
+
let fieldsWereSent = false;
|
|
90
|
+
const emit = ({ reachedEnd, rows, info }) => {
|
|
91
|
+
if (!info?.fields)
|
|
98
92
|
throw "No fields";
|
|
99
|
-
const fields = runSQL_1.getDetailedFieldInfo.bind(this.dboBuilder)(
|
|
100
|
-
const packet = { type: "data", rows:
|
|
93
|
+
const fields = runSQL_1.getDetailedFieldInfo.bind(this.dboBuilder)(info.fields);
|
|
94
|
+
const packet = { type: "data", rows, fields: fieldsWereSent ? undefined : fields, info: reachedEnd ? info : undefined, ended: reachedEnd, processId: processID };
|
|
101
95
|
socket.emit(channel, packet);
|
|
102
|
-
if (
|
|
103
|
-
|
|
104
|
-
throw "No result info";
|
|
105
|
-
runSQL_1.watchSchemaFallback.bind(this.dboBuilder)({ queryWithoutRLS: query.query, command: streamResult.command });
|
|
96
|
+
if (reachedEnd) {
|
|
97
|
+
runSQL_1.watchSchemaFallback.bind(this.dboBuilder)({ queryWithoutRLS: query.query, command: info.command });
|
|
106
98
|
}
|
|
99
|
+
fieldsWereSent = true;
|
|
107
100
|
};
|
|
108
101
|
const currentClient = client ?? this.getConnection(err => {
|
|
109
102
|
socketQuery.onError(err);
|
|
@@ -115,45 +108,46 @@ class QueryStreamer {
|
|
|
115
108
|
await currentClient.connect();
|
|
116
109
|
}
|
|
117
110
|
processID = currentClient.processID;
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
111
|
+
if (query.options?.streamLimit && (!Number.isInteger(query.options.streamLimit) || query.options.streamLimit < 0)) {
|
|
112
|
+
throw "streamLimit must be a positive integer";
|
|
113
|
+
}
|
|
114
|
+
const batchSize = query.options?.streamLimit ? Math.min(1e3, query.options?.streamLimit) : 1e3;
|
|
115
|
+
const cursor = currentClient.query(new Cursor(query.query, undefined, { rowMode: "array" }));
|
|
116
|
+
this.socketQueries[socketId][id].cursor = cursor;
|
|
117
|
+
let streamLimitReached = false;
|
|
118
|
+
let reachedEnd = false;
|
|
119
|
+
(async () => {
|
|
120
|
+
try {
|
|
121
|
+
let rowChunk = [];
|
|
122
|
+
let rowsSent = 0;
|
|
123
|
+
do {
|
|
124
|
+
rowChunk = await cursor.read(batchSize);
|
|
125
|
+
const info = (0, prostgles_types_1.pickKeys)(cursor._result, ["fields", "rowCount", "command", "duration"]);
|
|
126
|
+
rowsSent += rowChunk.length;
|
|
127
|
+
streamLimitReached = Boolean(query.options?.streamLimit && rowsSent >= query.options.streamLimit);
|
|
128
|
+
reachedEnd = rowChunk.length < batchSize;
|
|
129
|
+
emit({ info, rows: rowChunk, reachedEnd: reachedEnd || streamLimitReached });
|
|
130
|
+
} while (!reachedEnd && !streamLimitReached);
|
|
131
|
+
streamState = "ended";
|
|
132
|
+
if (!query.options?.persistStreamConnection) {
|
|
133
|
+
delete this.socketQueries[socketId]?.[id];
|
|
134
|
+
currentClient.end();
|
|
127
135
|
}
|
|
128
136
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
socketQuery.onError(error);
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
stream.on('end', () => {
|
|
148
|
-
const streamResult = getStreamResult();
|
|
149
|
-
streamState = "ended";
|
|
150
|
-
emit("ended", streamResult);
|
|
151
|
-
if (query.options?.persistStreamConnection) {
|
|
152
|
-
return;
|
|
137
|
+
catch (error) {
|
|
138
|
+
streamState = "errored";
|
|
139
|
+
if (error.message === "cannot insert multiple commands into a prepared statement") {
|
|
140
|
+
this.dboBuilder.dbo.sql(query.query, {}, { returnType: "arrayMode", hasParams: false }).then(res => {
|
|
141
|
+
emit({ info: (0, prostgles_types_1.omitKeys)(res, ["rows"]), reachedEnd: true, rows: res.rows });
|
|
142
|
+
}).catch(newError => {
|
|
143
|
+
socketQuery.onError(newError);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
socketQuery.onError(error);
|
|
148
|
+
}
|
|
153
149
|
}
|
|
154
|
-
|
|
155
|
-
currentClient.end();
|
|
156
|
-
});
|
|
150
|
+
})();
|
|
157
151
|
}
|
|
158
152
|
catch (err) {
|
|
159
153
|
socketQuery.onError(err);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryStreamer.js","sourceRoot":"","sources":["../../lib/DboBuilder/QueryStreamer.ts"],"names":[],"mappings":";;;AAAA,yBAAyB;
|
|
1
|
+
{"version":3,"file":"QueryStreamer.js","sourceRoot":"","sources":["../../lib/DboBuilder/QueryStreamer.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,28 +1,31 @@
|
|
|
1
1
|
import * as pg from "pg";
|
|
2
|
-
import
|
|
3
|
-
import { CHANNELS, SQLOptions, SocketSQLStreamPacket, SocketSQLStreamServer, omitKeys } from "prostgles-types";
|
|
2
|
+
import { CHANNELS, SQLOptions, SocketSQLStreamPacket, SocketSQLStreamServer, omitKeys, pickKeys } from "prostgles-types";
|
|
4
3
|
import { BasicCallback } from "../PubSubManager/PubSubManager";
|
|
5
4
|
import { DB } from "../initProstgles";
|
|
6
5
|
import { DboBuilder } from "./DboBuilder";
|
|
7
6
|
import { PRGLIOSocket } from "./DboBuilderTypes";
|
|
8
7
|
import { getErrorAsObject, getSerializedClientErrorFromPGError } from "./dboBuilderUtils";
|
|
9
8
|
import { getDetailedFieldInfo, watchSchemaFallback } from "./runSQL";
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
import CursorType from 'pg-cursor'
|
|
10
|
+
const Cursor: typeof CursorType = require('pg-cursor');
|
|
12
11
|
|
|
13
12
|
type ClientStreamedRequest = {
|
|
14
13
|
socket: PRGLIOSocket;
|
|
15
14
|
query: string;
|
|
16
15
|
options: SQLOptions | undefined;
|
|
17
16
|
persistConnection?: boolean;
|
|
18
|
-
|
|
19
17
|
}
|
|
20
18
|
type StreamedQuery = ClientStreamedRequest & {
|
|
21
|
-
|
|
19
|
+
cursor: CursorType | undefined;
|
|
22
20
|
client: pg.Client | undefined;
|
|
23
21
|
onError: ((error: any) => void);
|
|
24
22
|
}
|
|
25
|
-
type Info = {
|
|
23
|
+
type Info = {
|
|
24
|
+
command: string;
|
|
25
|
+
fields: any[];
|
|
26
|
+
rowCount: number;
|
|
27
|
+
duration: number;
|
|
28
|
+
};
|
|
26
29
|
|
|
27
30
|
const shortSocketIds: Record<string, number> = {};
|
|
28
31
|
const getSetShortSocketId = (socketId: string) => {
|
|
@@ -87,7 +90,7 @@ export class QueryStreamer {
|
|
|
87
90
|
...query,
|
|
88
91
|
id,
|
|
89
92
|
client: undefined,
|
|
90
|
-
|
|
93
|
+
cursor: undefined,
|
|
91
94
|
onError: (rawError: any) => {
|
|
92
95
|
if(errored) return;
|
|
93
96
|
errored = true;
|
|
@@ -100,7 +103,7 @@ export class QueryStreamer {
|
|
|
100
103
|
};
|
|
101
104
|
this.socketQueries[socketId]![id] ??= socketQuery;
|
|
102
105
|
let processID = -1;
|
|
103
|
-
let streamState: "started" | "ended" | undefined;
|
|
106
|
+
let streamState: "started" | "ended" | "errored" | undefined;
|
|
104
107
|
|
|
105
108
|
const startStream = async (client: pg.Client | undefined, query: ClientStreamedRequest) => {
|
|
106
109
|
const socketQuery = this.socketQueries[socketId]?.[id];
|
|
@@ -108,22 +111,17 @@ export class QueryStreamer {
|
|
|
108
111
|
throw "socket query not found";
|
|
109
112
|
}
|
|
110
113
|
|
|
111
|
-
|
|
112
|
-
let
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const
|
|
117
|
-
if(finished) return;
|
|
118
|
-
finished = finished || ended;
|
|
119
|
-
if(!streamResult?.fields) throw "No fields";
|
|
120
|
-
const fields = getDetailedFieldInfo.bind(this.dboBuilder)(streamResult.fields as any);
|
|
121
|
-
const packet: SocketSQLStreamPacket = { type: "data", rows: batchRows, fields, info: streamResult, ended, processId: processID };
|
|
114
|
+
/** Only send fields on first request */
|
|
115
|
+
let fieldsWereSent = false;
|
|
116
|
+
const emit = ({ reachedEnd, rows, info }: { reachedEnd: true; rows: any[]; info: Info } | { reachedEnd: false; rows: any[]; info: Omit<Info, "command"> }) => {
|
|
117
|
+
if(!info?.fields) throw "No fields";
|
|
118
|
+
const fields = getDetailedFieldInfo.bind(this.dboBuilder)(info.fields as any);
|
|
119
|
+
const packet: SocketSQLStreamPacket = { type: "data", rows, fields: fieldsWereSent? undefined : fields, info: reachedEnd? info : undefined, ended: reachedEnd, processId: processID };
|
|
122
120
|
socket.emit(channel, packet);
|
|
123
|
-
if(
|
|
124
|
-
|
|
125
|
-
watchSchemaFallback.bind(this.dboBuilder)({ queryWithoutRLS: query.query, command: streamResult.command });
|
|
121
|
+
if(reachedEnd){
|
|
122
|
+
watchSchemaFallback.bind(this.dboBuilder)({ queryWithoutRLS: query.query, command: info.command });
|
|
126
123
|
}
|
|
124
|
+
fieldsWereSent = true;
|
|
127
125
|
}
|
|
128
126
|
const currentClient = client ?? this.getConnection(err => {
|
|
129
127
|
socketQuery.onError(err);
|
|
@@ -134,46 +132,48 @@ export class QueryStreamer {
|
|
|
134
132
|
if(!client){
|
|
135
133
|
await currentClient.connect();
|
|
136
134
|
}
|
|
137
|
-
processID = (currentClient as any).processID
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
135
|
+
processID = (currentClient as any).processID;
|
|
136
|
+
|
|
137
|
+
if(query.options?.streamLimit && (!Number.isInteger(query.options.streamLimit) || query.options.streamLimit < 0)){
|
|
138
|
+
throw "streamLimit must be a positive integer";
|
|
139
|
+
}
|
|
140
|
+
const batchSize = query.options?.streamLimit? Math.min(1e3, query.options?.streamLimit) : 1e3;
|
|
141
|
+
const cursor = currentClient.query(new Cursor(query.query, undefined, { rowMode: "array" }));
|
|
142
|
+
this.socketQueries[socketId]![id]!.cursor = cursor;
|
|
143
|
+
let streamLimitReached = false;
|
|
144
|
+
let reachedEnd = false;
|
|
145
|
+
(async () => {
|
|
146
|
+
try {
|
|
147
|
+
let rowChunk: any[] = [];
|
|
148
|
+
let rowsSent = 0;
|
|
149
|
+
do {
|
|
150
|
+
rowChunk = await cursor.read(batchSize);
|
|
151
|
+
const info = pickKeys((cursor as any)._result, ["fields", "rowCount", "command", "duration"]) as Info;
|
|
152
|
+
rowsSent += rowChunk.length;
|
|
153
|
+
streamLimitReached = Boolean(query.options?.streamLimit && rowsSent >= query.options.streamLimit);
|
|
154
|
+
reachedEnd = rowChunk.length < batchSize;
|
|
155
|
+
emit({ info, rows: rowChunk, reachedEnd: reachedEnd || streamLimitReached });
|
|
156
|
+
} while (!reachedEnd && !streamLimitReached);
|
|
157
|
+
|
|
158
|
+
streamState = "ended";
|
|
159
|
+
|
|
160
|
+
if(!query.options?.persistStreamConnection){
|
|
161
|
+
delete this.socketQueries[socketId]?.[id];
|
|
162
|
+
currentClient.end();
|
|
163
|
+
}
|
|
164
|
+
} catch(error: any){
|
|
165
|
+
streamState = "errored";
|
|
166
|
+
if(error.message === "cannot insert multiple commands into a prepared statement") {
|
|
167
|
+
this.dboBuilder.dbo.sql!(query.query, {}, { returnType: "arrayMode", hasParams: false }).then(res => {
|
|
168
|
+
emit({ info: omitKeys(res, ["rows"]), reachedEnd: true, rows: res.rows});
|
|
169
|
+
}).catch(newError => {
|
|
170
|
+
socketQuery.onError(newError);
|
|
171
|
+
});
|
|
172
|
+
} else {
|
|
173
|
+
socketQuery.onError(error);
|
|
147
174
|
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
emit("rows", getStreamResult());
|
|
151
|
-
batchRows = [];
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
stream.on('error', error => {
|
|
155
|
-
if(error.message === "cannot insert multiple commands into a prepared statement") {
|
|
156
|
-
this.dboBuilder.dbo.sql!(query.query, {}, { returnType: "arrayMode", hasParams: false }).then(res => {
|
|
157
|
-
batchRows.push(res.rows);
|
|
158
|
-
emit("ended", res);
|
|
159
|
-
}).catch(newError => {
|
|
160
|
-
socketQuery.onError(newError);
|
|
161
|
-
});
|
|
162
|
-
} else {
|
|
163
|
-
socketQuery.onError(error);
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
stream.on('end', () => {
|
|
167
|
-
const streamResult = getStreamResult();
|
|
168
|
-
streamState = "ended";
|
|
169
|
-
emit("ended", streamResult);
|
|
170
|
-
|
|
171
|
-
if(query.options?.persistStreamConnection){
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
delete this.socketQueries[socketId]?.[id];
|
|
175
|
-
currentClient.end();
|
|
176
|
-
});
|
|
175
|
+
}
|
|
176
|
+
})()
|
|
177
177
|
} catch(err){
|
|
178
178
|
socketQuery.onError(err);
|
|
179
179
|
await currentClient.end();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prostgles-server",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.144",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
"check-disk-space": "^3.3.1",
|
|
44
44
|
"file-type": "^18.5.0",
|
|
45
45
|
"pg": "^8.11.3",
|
|
46
|
+
"pg-cursor": "^2.10.3",
|
|
46
47
|
"pg-promise": "^11.5.4",
|
|
47
|
-
"pg-query-stream": "^4.5.3",
|
|
48
48
|
"prostgles-client": "^4.0.53",
|
|
49
49
|
"prostgles-types": "^4.0.67"
|
|
50
50
|
},
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"@types/bluebird": "^3.5.36",
|
|
53
53
|
"@types/file-type": "^10.9.1",
|
|
54
54
|
"@types/node": "^18.0.3",
|
|
55
|
+
"@types/pg-cursor": "^2.7.2",
|
|
55
56
|
"@types/sharp": "^0.30.4",
|
|
56
57
|
"@types/socket.io": "^3.0.2",
|
|
57
58
|
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"start": "tsc-watch --onSuccess \"node dist/client/index.js\"",
|
|
8
8
|
"dev": "NOSTOP=true npm start",
|
|
9
9
|
"build": "rm -rf ./node_modules/* && rm -rf ./dist/* && npm i && tsc",
|
|
10
|
-
"test": "node
|
|
10
|
+
"test": "node dist/client/index.js"
|
|
11
11
|
},
|
|
12
12
|
"author": "",
|
|
13
13
|
"license": "ISC",
|
|
@@ -7,7 +7,7 @@ import { reject } from 'bluebird';
|
|
|
7
7
|
export default async function client_only(db: DBHandlerClient, auth: Auth, log: (...args: any[]) => any, methods, tableSchema: DBSchemaTable[], token: string){
|
|
8
8
|
|
|
9
9
|
await tryRunP("SQL Stream stop kills the query", async (resolve, reject) => {
|
|
10
|
-
const query = "SELECT * FROM pg_sleep(5)"
|
|
10
|
+
const query = "SELECT * FROM pg_sleep(5)";
|
|
11
11
|
const res = await db.sql!(query, {}, { returnType: "stream" });
|
|
12
12
|
const listener = async (packet: SocketSQLStreamPacket) => {
|
|
13
13
|
if(packet.type === "error"){
|
|
@@ -19,8 +19,8 @@ export default async function client_only(db: DBHandlerClient, auth: Auth, log:
|
|
|
19
19
|
} else {
|
|
20
20
|
assert.equal(packet.type, "data");
|
|
21
21
|
assert.equal(packet.ended, true);
|
|
22
|
-
assert.deepStrictEqual(packet.rows, []);
|
|
23
|
-
reject("
|
|
22
|
+
assert.deepStrictEqual(packet.rows, [['']]);
|
|
23
|
+
reject("SQL Stream stop kills the query");
|
|
24
24
|
}
|
|
25
25
|
};
|
|
26
26
|
const startHandler = await res.start(listener);
|
|
@@ -29,6 +29,21 @@ export default async function client_only(db: DBHandlerClient, auth: Auth, log:
|
|
|
29
29
|
}, 1000);
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
+
await tryRunP("SQL Stream limit works", async (resolve, reject) => {
|
|
33
|
+
const res = await db.sql!("SELECT * FROM generate_series(1, 1e5)", {}, { returnType: "stream", streamLimit: 10 });
|
|
34
|
+
const listener = async (packet: SocketSQLStreamPacket) => {
|
|
35
|
+
if(packet.type === "error"){
|
|
36
|
+
reject(packet.error);
|
|
37
|
+
} else {
|
|
38
|
+
assert.equal(packet.type, "data");
|
|
39
|
+
assert.equal(packet.ended, true);
|
|
40
|
+
assert.equal(packet.rows.length, 10);
|
|
41
|
+
resolve("ok");
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
await res.start(listener);
|
|
45
|
+
});
|
|
46
|
+
|
|
32
47
|
await tryRunP("SQL Stream stop with terminate kills the query", async (resolve, reject) => {
|
|
33
48
|
const totalRows = 5e6;
|
|
34
49
|
const query = `SELECT * FROM generate_series(1, ${totalRows})`;
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
},
|
|
22
22
|
"../..": {
|
|
23
23
|
"name": "prostgles-server",
|
|
24
|
-
"version": "4.1.
|
|
24
|
+
"version": "4.1.143",
|
|
25
25
|
"license": "MIT",
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@types/express": "^4.17.13",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"check-disk-space": "^3.3.1",
|
|
33
33
|
"file-type": "^18.5.0",
|
|
34
34
|
"pg": "^8.11.3",
|
|
35
|
+
"pg-cursor": "^2.10.3",
|
|
35
36
|
"pg-promise": "^11.5.4",
|
|
36
|
-
"pg-query-stream": "^4.5.3",
|
|
37
37
|
"prostgles-client": "^4.0.53",
|
|
38
38
|
"prostgles-types": "^4.0.67"
|
|
39
39
|
},
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"@types/bluebird": "^3.5.36",
|
|
42
42
|
"@types/file-type": "^10.9.1",
|
|
43
43
|
"@types/node": "^18.0.3",
|
|
44
|
+
"@types/pg-cursor": "^2.7.2",
|
|
44
45
|
"@types/sharp": "^0.30.4",
|
|
45
46
|
"@types/socket.io": "^3.0.2",
|
|
46
47
|
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
|
@@ -1533,6 +1534,7 @@
|
|
|
1533
1534
|
"@types/json-schema": "^7.0.11",
|
|
1534
1535
|
"@types/node": "^18.0.3",
|
|
1535
1536
|
"@types/pg": "^8.10.9",
|
|
1537
|
+
"@types/pg-cursor": "^2.7.2",
|
|
1536
1538
|
"@types/sharp": "^0.30.4",
|
|
1537
1539
|
"@types/socket.io": "^3.0.2",
|
|
1538
1540
|
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
|
@@ -1543,8 +1545,8 @@
|
|
|
1543
1545
|
"eslint": "^8.51.0",
|
|
1544
1546
|
"file-type": "^18.5.0",
|
|
1545
1547
|
"pg": "^8.11.3",
|
|
1548
|
+
"pg-cursor": "^2.10.3",
|
|
1546
1549
|
"pg-promise": "^11.5.4",
|
|
1547
|
-
"pg-query-stream": "^4.5.3",
|
|
1548
1550
|
"prostgles-client": "^4.0.53",
|
|
1549
1551
|
"prostgles-types": "^4.0.67",
|
|
1550
1552
|
"typescript": "^5.2.2"
|