prostgles-server 4.1.128 → 4.1.129
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 -3
- package/dist/DboBuilder/QueryStreamer.d.ts.map +1 -1
- package/dist/DboBuilder/QueryStreamer.js +91 -103
- package/dist/DboBuilder/QueryStreamer.js.map +1 -1
- package/lib/DboBuilder/QueryStreamer.ts +88 -99
- package/package.json +1 -1
- package/tests/client_only_queries.ts +51 -51
- package/tests/server/package-lock.json +1 -1
|
@@ -12,16 +12,15 @@ type ClientStreamedRequest = {
|
|
|
12
12
|
};
|
|
13
13
|
type StreamedQuery = ClientStreamedRequest & {
|
|
14
14
|
stream: QueryStreamType | undefined;
|
|
15
|
-
|
|
15
|
+
client: pg.Client | undefined;
|
|
16
16
|
onError: ((error: any) => void);
|
|
17
17
|
};
|
|
18
18
|
export declare class QueryStreamer {
|
|
19
19
|
db: DB;
|
|
20
20
|
dboBuilder: DboBuilder;
|
|
21
21
|
socketQueries: Record<string, Record<string, StreamedQuery>>;
|
|
22
|
-
pool: pg.Pool;
|
|
23
|
-
adminPool: pg.Pool;
|
|
24
22
|
constructor(dboBuilder: DboBuilder);
|
|
23
|
+
getConnection: (onError: ((err: any) => void) | undefined) => pg.Client;
|
|
25
24
|
create: (query: ClientStreamedRequest) => Promise<SocketSQLStreamServer>;
|
|
26
25
|
}
|
|
27
26
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryStreamer.d.ts","sourceRoot":"","sources":["../../lib/DboBuilder/QueryStreamer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACtC,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAAY,UAAU,EAAyB,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACrG,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGjD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,eAAe,MAAM,iBAAiB,CAAC;AAK9C,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;CAE7B,CAAA;AACD,KAAK,aAAa,GAAG,qBAAqB,GAAG;IAC3C,MAAM,EAAE,eAAe,GAAG,SAAS,CAAC;IACpC,
|
|
1
|
+
{"version":3,"file":"QueryStreamer.d.ts","sourceRoot":"","sources":["../../lib/DboBuilder/QueryStreamer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACtC,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAAY,UAAU,EAAyB,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACrG,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGjD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,eAAe,MAAM,iBAAiB,CAAC;AAK9C,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;CAE7B,CAAA;AACD,KAAK,aAAa,GAAG,qBAAqB,GAAG;IAC3C,MAAM,EAAE,eAAe,GAAG,SAAS,CAAC;IACpC,MAAM,EAAE,EAAE,CAAC,MAAM,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC,CAAC;CACjC,CAAA;AAWD,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;gBACtD,UAAU,EAAE,UAAU;IAKlC,aAAa,mBAAoB,GAAG,KAAK,IAAI,4BAO5C;IAED,MAAM,UAAiB,qBAAqB,KAAG,QAAQ,qBAAqB,CAAC,CAqJ5E;CACF"}
|
|
@@ -18,26 +18,18 @@ class QueryStreamer {
|
|
|
18
18
|
db;
|
|
19
19
|
dboBuilder;
|
|
20
20
|
socketQueries = {};
|
|
21
|
-
pool;
|
|
22
|
-
adminPool;
|
|
23
21
|
constructor(dboBuilder) {
|
|
24
22
|
this.dboBuilder = dboBuilder;
|
|
25
23
|
this.db = dboBuilder.db;
|
|
24
|
+
}
|
|
25
|
+
getConnection = (onError) => {
|
|
26
26
|
const connectionInfo = typeof this.db.$cn === "string" ? { connectionString: this.db.$cn } : this.db.$cn;
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
this.pool = new pg.Pool({ ...connectionInfo, max: 50 }).on("error", (error) => {
|
|
31
|
-
// if(error.message !== "Connection terminated") return;
|
|
32
|
-
Object.entries(this.socketQueries).forEach(([socketId, queries]) => {
|
|
33
|
-
Object.entries(queries).forEach(([id, query]) => {
|
|
34
|
-
query.onError?.({ message: error.message });
|
|
35
|
-
delete this.socketQueries[socketId]?.[id];
|
|
36
|
-
});
|
|
37
|
-
});
|
|
27
|
+
const client = new pg.Client(connectionInfo);
|
|
28
|
+
client.on("error", (err) => {
|
|
29
|
+
onError?.(err);
|
|
38
30
|
});
|
|
39
|
-
|
|
40
|
-
}
|
|
31
|
+
return client;
|
|
32
|
+
};
|
|
41
33
|
create = async (query) => {
|
|
42
34
|
const { socket, persistConnection } = query;
|
|
43
35
|
const socketId = socket.id;
|
|
@@ -51,7 +43,7 @@ class QueryStreamer {
|
|
|
51
43
|
let errored = false;
|
|
52
44
|
const socketQuery = {
|
|
53
45
|
...query,
|
|
54
|
-
|
|
46
|
+
client: undefined,
|
|
55
47
|
stream: undefined,
|
|
56
48
|
onError: (rawError) => {
|
|
57
49
|
if (errored)
|
|
@@ -71,102 +63,98 @@ class QueryStreamer {
|
|
|
71
63
|
if (!socketQuery) {
|
|
72
64
|
throw "socket query not found";
|
|
73
65
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if (!
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
66
|
+
let emittedPackets = 0;
|
|
67
|
+
let batchRows = [];
|
|
68
|
+
let finished = false;
|
|
69
|
+
const batchSize = 10000;
|
|
70
|
+
let stream;
|
|
71
|
+
let poolClient;
|
|
72
|
+
const emit = (type, stream) => {
|
|
73
|
+
const result = stream?._result;
|
|
74
|
+
let packet;
|
|
75
|
+
const ended = type === "ended";
|
|
76
|
+
if (finished)
|
|
77
|
+
return;
|
|
78
|
+
finished = finished || ended;
|
|
79
|
+
if (!emittedPackets) {
|
|
80
|
+
if (!result?.fields)
|
|
81
|
+
throw "No fields";
|
|
82
|
+
const fields = runSQL_1.getDetailedFieldInfo.bind(this.dboBuilder)(result.fields);
|
|
83
|
+
packet = { type: "start", rows: batchRows, fields, ended, processId: processID };
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
packet = { type: "rows", rows: batchRows, ended };
|
|
87
|
+
}
|
|
88
|
+
socket.emit(channel, packet);
|
|
89
|
+
if (ended) {
|
|
90
|
+
if (!result)
|
|
91
|
+
throw "No result info";
|
|
92
|
+
runSQL_1.watchSchemaFallback.bind(this.dboBuilder)({ queryWithoutRLS: query.query, command: result.command });
|
|
93
|
+
}
|
|
94
|
+
emittedPackets++;
|
|
95
|
+
};
|
|
96
|
+
const client = this.getConnection(err => {
|
|
97
|
+
socketQuery.onError(err);
|
|
98
|
+
client.end();
|
|
99
|
+
});
|
|
100
|
+
try {
|
|
101
|
+
await client.connect();
|
|
102
|
+
poolClient = client;
|
|
103
|
+
processID = client.processID;
|
|
104
|
+
const queryStream = new QueryStream(query.query, [], { batchSize: 1e6, highWaterMark: 1e6, rowMode: "array" });
|
|
105
|
+
stream = client.query(queryStream);
|
|
106
|
+
this.socketQueries[socketId][id].client = poolClient;
|
|
107
|
+
this.socketQueries[socketId][id].stream = stream;
|
|
108
|
+
stream.on('data', async (data) => {
|
|
109
|
+
batchRows.push(data);
|
|
110
|
+
if (options?.streamLimit) {
|
|
111
|
+
if (batchRows.length >= options.streamLimit) {
|
|
112
|
+
emit("ended", stream);
|
|
113
|
+
}
|
|
93
114
|
}
|
|
94
|
-
|
|
95
|
-
|
|
115
|
+
if (batchRows.length >= batchSize) {
|
|
116
|
+
emit("rows", stream);
|
|
117
|
+
batchRows = [];
|
|
96
118
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
119
|
+
});
|
|
120
|
+
stream.on('error', error => {
|
|
121
|
+
socketQuery.onError(error);
|
|
122
|
+
});
|
|
123
|
+
stream.on('end', () => {
|
|
124
|
+
emit("ended", stream);
|
|
125
|
+
// release the client when the stream is finished AND connection is not persisted
|
|
126
|
+
if (!options?.persistStreamConnection) {
|
|
127
|
+
delete this.socketQueries[socketId]?.[id];
|
|
128
|
+
client.end();
|
|
102
129
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (!client)
|
|
110
|
-
throw "No client";
|
|
111
|
-
poolClient = client;
|
|
112
|
-
processID = client.processID;
|
|
113
|
-
const queryStream = new QueryStream(query.query, [], { batchSize, rowMode: "array" });
|
|
114
|
-
stream = client.query(queryStream);
|
|
115
|
-
this.socketQueries[socketId][id].poolClient = poolClient;
|
|
116
|
-
this.socketQueries[socketId][id].stream = stream;
|
|
117
|
-
stream.on('data', async (data) => {
|
|
118
|
-
batchRows.push(data);
|
|
119
|
-
if (options?.streamLimit) {
|
|
120
|
-
if (batchRows.length >= options.streamLimit) {
|
|
121
|
-
emit("ended", stream);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
if (batchRows.length >= batchSize) {
|
|
125
|
-
emit("rows", stream);
|
|
126
|
-
batchRows = [];
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
stream.on('error', error => {
|
|
130
|
-
socketQuery.onError(error);
|
|
131
|
-
});
|
|
132
|
-
stream.on('end', () => {
|
|
133
|
-
emit("ended", stream);
|
|
134
|
-
// release the client when the stream is finished
|
|
135
|
-
if (!options?.persistStreamConnection) {
|
|
136
|
-
delete this.socketQueries[socketId]?.[id];
|
|
137
|
-
done();
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
catch (err) {
|
|
143
|
-
socketQuery.onError(err);
|
|
144
|
-
}
|
|
145
|
-
})();
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
catch (err) {
|
|
133
|
+
socketQuery.onError(err);
|
|
134
|
+
await client.end();
|
|
135
|
+
}
|
|
146
136
|
};
|
|
147
|
-
const stop = (opts, cb) => {
|
|
148
|
-
|
|
149
|
-
const { stream, poolClient } = this.socketQueries[socketId]?.[id] ?? {};
|
|
137
|
+
const stop = async (opts, cb) => {
|
|
138
|
+
const { stream, client: poolClient } = this.socketQueries[socketId]?.[id] ?? {};
|
|
150
139
|
if (!stream || !poolClient)
|
|
151
140
|
return;
|
|
152
|
-
this.
|
|
153
|
-
|
|
154
|
-
|
|
141
|
+
const client = this.getConnection(undefined);
|
|
142
|
+
try {
|
|
143
|
+
await client.connect();
|
|
155
144
|
if (!client)
|
|
156
145
|
return cb(null, "No client");
|
|
157
146
|
const stopFunction = opts?.terminate ? "pg_terminate_backend" : "pg_cancel_backend";
|
|
158
|
-
client.query(`SELECT ${stopFunction}(pid) FROM pg_stat_activity WHERE pid = $1`, [processID
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
});
|
|
147
|
+
const rows = await client.query(`SELECT ${stopFunction}(pid), pid, state, query FROM pg_stat_activity WHERE pid = $1 AND query = $2`, [processID, query.query]);
|
|
148
|
+
socket.removeAllListeners(unsubChannel);
|
|
149
|
+
socket.removeAllListeners(channel);
|
|
150
|
+
cb({ processID, info: rows.rows[0] });
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
cb(null, error);
|
|
154
|
+
}
|
|
155
|
+
finally {
|
|
156
|
+
await client.end();
|
|
157
|
+
}
|
|
170
158
|
};
|
|
171
159
|
socket.removeAllListeners(unsubChannel);
|
|
172
160
|
socket.once(unsubChannel, stop);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryStreamer.js","sourceRoot":"","sources":["../../lib/DboBuilder/QueryStreamer.ts"],"names":[],"mappings":";;;AACA,yBAAyB;AACzB,qDAAqG;AAErG,uDAAwE;AACxE,qCAAqE;AAIrE,MAAM,WAAW,GAA2B,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAgBvE,MAAM,cAAc,GAA2B,EAAE,CAAC;AAClD,MAAM,mBAAmB,GAAG,CAAC,QAAgB,EAAE,EAAE;IAC/C,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACrC,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,CAAC;IACzB,cAAc,CAAC,OAAO,CAAC,GAAG,KAAK,CAAC;IAChC,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF,MAAa,aAAa;IACxB,EAAE,CAAK;IACP,UAAU,CAAa;IACvB,aAAa,GAAkD,EAAE,CAAC;IAClE,
|
|
1
|
+
{"version":3,"file":"QueryStreamer.js","sourceRoot":"","sources":["../../lib/DboBuilder/QueryStreamer.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,7 +19,7 @@ type ClientStreamedRequest = {
|
|
|
19
19
|
}
|
|
20
20
|
type StreamedQuery = ClientStreamedRequest & {
|
|
21
21
|
stream: QueryStreamType | undefined;
|
|
22
|
-
|
|
22
|
+
client: pg.Client | undefined;
|
|
23
23
|
onError: ((error: any) => void);
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -36,25 +36,18 @@ export class QueryStreamer {
|
|
|
36
36
|
db: DB;
|
|
37
37
|
dboBuilder: DboBuilder;
|
|
38
38
|
socketQueries: Record<string, Record<string, StreamedQuery>> = {};
|
|
39
|
-
pool: pg.Pool;
|
|
40
|
-
adminPool: pg.Pool;
|
|
41
39
|
constructor(dboBuilder: DboBuilder) {
|
|
42
40
|
this.dboBuilder = dboBuilder;
|
|
43
41
|
this.db = dboBuilder.db;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
getConnection = (onError: ((err: any) => void) | undefined) => {
|
|
44
45
|
const connectionInfo = typeof this.db.$cn === "string"? { connectionString: this.db.$cn } : this.db.$cn as any;
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
this.pool = new pg.Pool({ ...connectionInfo, max: 50 }).on("error", (error) => {
|
|
49
|
-
// if(error.message !== "Connection terminated") return;
|
|
50
|
-
Object.entries(this.socketQueries).forEach(([socketId, queries]) => {
|
|
51
|
-
Object.entries(queries).forEach(([id, query]) => {
|
|
52
|
-
query.onError?.({ message: error.message });
|
|
53
|
-
delete this.socketQueries[socketId]?.[id];
|
|
54
|
-
});
|
|
55
|
-
});
|
|
46
|
+
const client = new pg.Client(connectionInfo);
|
|
47
|
+
client.on("error", (err) => {
|
|
48
|
+
onError?.(err);
|
|
56
49
|
});
|
|
57
|
-
|
|
50
|
+
return client;
|
|
58
51
|
}
|
|
59
52
|
|
|
60
53
|
create = async (query: ClientStreamedRequest): Promise<SocketSQLStreamServer> => {
|
|
@@ -71,7 +64,7 @@ export class QueryStreamer {
|
|
|
71
64
|
let errored = false;
|
|
72
65
|
const socketQuery = {
|
|
73
66
|
...query,
|
|
74
|
-
|
|
67
|
+
client: undefined,
|
|
75
68
|
stream: undefined,
|
|
76
69
|
onError: (rawError: any) => {
|
|
77
70
|
if(errored) return;
|
|
@@ -86,101 +79,97 @@ export class QueryStreamer {
|
|
|
86
79
|
this.socketQueries[socketId]![id] ??= socketQuery;
|
|
87
80
|
const { options } = query
|
|
88
81
|
let processID = -1;
|
|
82
|
+
|
|
89
83
|
const startStream = async () => {
|
|
90
84
|
const socketQuery = this.socketQueries[socketId]?.[id];
|
|
91
85
|
if(!socketQuery){
|
|
92
86
|
throw "socket query not found";
|
|
87
|
+
}
|
|
88
|
+
let emittedPackets = 0;
|
|
89
|
+
let batchRows: any[] = [];
|
|
90
|
+
let finished = false;
|
|
91
|
+
const batchSize = 10000;
|
|
92
|
+
let stream: QueryStreamType;
|
|
93
|
+
let poolClient: pg.Client;
|
|
94
|
+
const emit = (type: "rows" | "ended", stream: QueryStreamType | undefined) => {
|
|
95
|
+
const result = stream?._result as { command: string; fields: any[] } | undefined;
|
|
96
|
+
let packet: SocketSQLStreamPacket | undefined;
|
|
97
|
+
const ended = type === "ended";
|
|
98
|
+
if(finished) return;
|
|
99
|
+
finished = finished || ended;
|
|
100
|
+
if (!emittedPackets) {
|
|
101
|
+
if(!result?.fields) throw "No fields";
|
|
102
|
+
const fields = getDetailedFieldInfo.bind(this.dboBuilder)(result.fields as any);
|
|
103
|
+
packet = { type: "start", rows: batchRows, fields, ended, processId: processID };
|
|
104
|
+
} else {
|
|
105
|
+
packet = { type: "rows", rows: batchRows, ended };
|
|
106
|
+
}
|
|
107
|
+
socket.emit(channel, packet);
|
|
108
|
+
if(ended){
|
|
109
|
+
if(!result) throw "No result info";
|
|
110
|
+
watchSchemaFallback.bind(this.dboBuilder)({ queryWithoutRLS: query.query, command: result.command });
|
|
111
|
+
}
|
|
112
|
+
emittedPackets++;
|
|
93
113
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
packet = { type: "rows", rows: batchRows, ended };
|
|
114
|
+
const client = this.getConnection(err => {
|
|
115
|
+
socketQuery.onError(err);
|
|
116
|
+
client.end();
|
|
117
|
+
});
|
|
118
|
+
try {
|
|
119
|
+
await client.connect();
|
|
120
|
+
poolClient = client;
|
|
121
|
+
processID = (client as any).processID
|
|
122
|
+
const queryStream = new QueryStream(query.query, [], { batchSize: 1e6, highWaterMark: 1e6, rowMode: "array" });
|
|
123
|
+
stream = client.query(queryStream);
|
|
124
|
+
this.socketQueries[socketId]![id]!.client = poolClient;
|
|
125
|
+
this.socketQueries[socketId]![id]!.stream = stream;
|
|
126
|
+
stream.on('data', async (data) => {
|
|
127
|
+
batchRows.push(data);
|
|
128
|
+
if(options?.streamLimit) {
|
|
129
|
+
if(batchRows.length >= options.streamLimit){
|
|
130
|
+
emit("ended", stream);
|
|
131
|
+
}
|
|
113
132
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
watchSchemaFallback.bind(this.dboBuilder)({ queryWithoutRLS: query.query, command: result.command });
|
|
133
|
+
if (batchRows.length >= batchSize) {
|
|
134
|
+
emit("rows", stream);
|
|
135
|
+
batchRows = [];
|
|
118
136
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
if(batchRows.length >= options.streamLimit){
|
|
137
|
-
emit("ended", stream);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
if (batchRows.length >= batchSize) {
|
|
141
|
-
emit("rows", stream);
|
|
142
|
-
batchRows = [];
|
|
143
|
-
}
|
|
144
|
-
});
|
|
145
|
-
stream.on('error', error => {
|
|
146
|
-
socketQuery.onError(error);
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
stream.on('end', () => {
|
|
150
|
-
emit("ended", stream);
|
|
151
|
-
// release the client when the stream is finished
|
|
152
|
-
if(!options?.persistStreamConnection){
|
|
153
|
-
delete this.socketQueries[socketId]?.[id];
|
|
154
|
-
done();
|
|
155
|
-
}
|
|
156
|
-
})
|
|
157
|
-
});
|
|
158
|
-
} catch(err){
|
|
159
|
-
socketQuery.onError(err);
|
|
160
|
-
}
|
|
161
|
-
})();
|
|
137
|
+
});
|
|
138
|
+
stream.on('error', error => {
|
|
139
|
+
socketQuery.onError(error);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
stream.on('end', () => {
|
|
143
|
+
emit("ended", stream);
|
|
144
|
+
// release the client when the stream is finished AND connection is not persisted
|
|
145
|
+
if(!options?.persistStreamConnection){
|
|
146
|
+
delete this.socketQueries[socketId]?.[id];
|
|
147
|
+
client.end();
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
} catch(err){
|
|
151
|
+
socketQuery.onError(err);
|
|
152
|
+
await client.end();
|
|
153
|
+
}
|
|
162
154
|
}
|
|
163
155
|
|
|
164
|
-
const stop = (opts: { terminate?: boolean; } | undefined, cb: BasicCallback) => {
|
|
165
|
-
|
|
166
|
-
const { stream, poolClient } = this.socketQueries[socketId]?.[id] ?? {};
|
|
156
|
+
const stop = async (opts: { terminate?: boolean; } | undefined, cb: BasicCallback) => {
|
|
157
|
+
const { stream, client: poolClient } = this.socketQueries[socketId]?.[id] ?? {};
|
|
167
158
|
if(!stream || !poolClient) return;
|
|
168
|
-
this.
|
|
169
|
-
|
|
159
|
+
const client = this.getConnection(undefined);
|
|
160
|
+
try {
|
|
161
|
+
await client.connect();
|
|
170
162
|
if (!client) return cb(null, "No client");
|
|
171
163
|
const stopFunction = opts?.terminate? "pg_terminate_backend" : "pg_cancel_backend";
|
|
172
|
-
client.query(`SELECT ${stopFunction}(pid) FROM pg_stat_activity WHERE pid = $1`, [processID
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
done();
|
|
182
|
-
});
|
|
183
|
-
});
|
|
164
|
+
const rows = await client.query(`SELECT ${stopFunction}(pid), pid, state, query FROM pg_stat_activity WHERE pid = $1 AND query = $2`, [processID, query.query]);
|
|
165
|
+
socket.removeAllListeners(unsubChannel);
|
|
166
|
+
socket.removeAllListeners(channel);
|
|
167
|
+
cb({ processID, info: rows.rows[0] });
|
|
168
|
+
} catch (error){
|
|
169
|
+
cb(null, error);
|
|
170
|
+
} finally {
|
|
171
|
+
await client.end();
|
|
172
|
+
}
|
|
184
173
|
}
|
|
185
174
|
|
|
186
175
|
socket.removeAllListeners(unsubChannel);
|
package/package.json
CHANGED
|
@@ -5,6 +5,57 @@ import { tryRun, tryRunP } from './isomorphic_queries';
|
|
|
5
5
|
import { reject } from 'bluebird';
|
|
6
6
|
|
|
7
7
|
export default async function client_only(db: DBHandlerClient, auth: Auth, log: (...args: any[]) => any, methods, tableSchema: DBSchemaTable[], token: string){
|
|
8
|
+
|
|
9
|
+
await tryRunP("SQL Stream stop kills the query", async (resolve, reject) => {
|
|
10
|
+
const query = "SELECT * FROM pg_sleep(5)"
|
|
11
|
+
const res = await db.sql!(query, {}, { returnType: "stream" });
|
|
12
|
+
const listener = async (packet: SocketSQLStreamPacket) => {
|
|
13
|
+
if(packet.type === "error"){
|
|
14
|
+
const queryState = await db.sql!("SELECT * FROM pg_stat_activity WHERE query = $1", [query], { returnType: "rows" });
|
|
15
|
+
assert.equal(queryState.length, 1);
|
|
16
|
+
assert.equal(queryState[0].state, "idle");
|
|
17
|
+
assert.equal(packet.error.message, "canceling statement due to user request");
|
|
18
|
+
resolve("ok");
|
|
19
|
+
} else {
|
|
20
|
+
assert.equal(packet.type, "start");
|
|
21
|
+
assert.equal(packet.ended, true);
|
|
22
|
+
assert.deepStrictEqual(packet.rows, []);
|
|
23
|
+
reject("ok");
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const startHandler = await res.start(listener);
|
|
27
|
+
setTimeout(() => {
|
|
28
|
+
startHandler.stop().catch(reject);
|
|
29
|
+
}, 1000);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
await tryRunP("SQL Stream stop with terminate kills the query", async (resolve, reject) => {
|
|
33
|
+
const totalRows = 5e6;
|
|
34
|
+
const query = `SELECT * FROM generate_series(1, ${totalRows})`;
|
|
35
|
+
const res = await db.sql!(query, {}, { returnType: "stream" });
|
|
36
|
+
const rowsReceived: any[] = [];
|
|
37
|
+
const listener = async (packet: SocketSQLStreamPacket) => {
|
|
38
|
+
if(packet.type === "error"){
|
|
39
|
+
const queryState = await db.sql!("SELECT * FROM pg_stat_activity WHERE query = $1", [query], { returnType: "rows" });
|
|
40
|
+
assert.equal(queryState.length, 0);
|
|
41
|
+
resolve("ok");
|
|
42
|
+
} else {
|
|
43
|
+
try {
|
|
44
|
+
rowsReceived.push(...packet.rows);
|
|
45
|
+
console.log(rowsReceived.length)
|
|
46
|
+
assert.equal(packet.ended, false);
|
|
47
|
+
assert.equal(rowsReceived.length < totalRows, true);
|
|
48
|
+
} catch(error){
|
|
49
|
+
reject(error);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const startHandler = await res.start(listener);
|
|
54
|
+
setTimeout(() => {
|
|
55
|
+
startHandler.stop(true).catch(reject);
|
|
56
|
+
}, 22);
|
|
57
|
+
});
|
|
58
|
+
|
|
8
59
|
await Promise.all([1e3, 1e2].map(async (numberOfRows) => {
|
|
9
60
|
await tryRunP("SQL Stream", async (resolve) => {
|
|
10
61
|
const res = await db.sql!(`SELECT v.* FROM generate_series(1, ${numberOfRows}) v`, {}, { returnType: "stream" });
|
|
@@ -112,57 +163,6 @@ export default async function client_only(db: DBHandlerClient, auth: Auth, log:
|
|
|
112
163
|
await res.start(listener);
|
|
113
164
|
});
|
|
114
165
|
|
|
115
|
-
await tryRunP("SQL Stream stop kills the query", async (resolve, reject) => {
|
|
116
|
-
const query = "SELECT * FROM pg_sleep(5)"
|
|
117
|
-
const res = await db.sql!(query, {}, { returnType: "stream" });
|
|
118
|
-
const listener = async (packet: SocketSQLStreamPacket) => {
|
|
119
|
-
if(packet.type === "error"){
|
|
120
|
-
const queryState = await db.sql!("SELECT * FROM pg_stat_activity WHERE query = $1", [query], { returnType: "rows" });
|
|
121
|
-
assert.equal(queryState.length, 1);
|
|
122
|
-
assert.equal(queryState[0].state, "idle");
|
|
123
|
-
assert.equal(packet.error.message, "canceling statement due to user request");
|
|
124
|
-
resolve("ok");
|
|
125
|
-
} else {
|
|
126
|
-
assert.equal(packet.type, "start");
|
|
127
|
-
assert.equal(packet.ended, true);
|
|
128
|
-
assert.deepStrictEqual(packet.rows, []);
|
|
129
|
-
reject("ok");
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
const startHandler = await res.start(listener);
|
|
133
|
-
setTimeout(() => {
|
|
134
|
-
startHandler.stop().catch(reject);
|
|
135
|
-
}, 1000);
|
|
136
|
-
});
|
|
137
|
-
// await tryRunP("SQL Stream stop with terminate kills the query", async (resolve, reject) => {
|
|
138
|
-
// const totalRows = 5e6;
|
|
139
|
-
// const query = `SELECT * FROM generate_series(1, ${totalRows})`;
|
|
140
|
-
// const res = await db.sql!(query, {}, { returnType: "stream" });
|
|
141
|
-
// const rowsReceived: any[] = [];
|
|
142
|
-
// const listener = async (packet: SocketSQLStreamPacket) => {
|
|
143
|
-
// if(packet.type === "error"){
|
|
144
|
-
// const queryState = await db.sql!("SELECT * FROM pg_stat_activity WHERE query = $1", [query], { returnType: "rows" });
|
|
145
|
-
// assert.equal(queryState.length, 1);
|
|
146
|
-
// assert.equal(queryState[0].state, "idle");
|
|
147
|
-
// assert.equal(packet.error.message, "canceling statement due to user request");
|
|
148
|
-
// resolve("ok");
|
|
149
|
-
// } else {
|
|
150
|
-
// try {
|
|
151
|
-
// rowsReceived.push(...packet.rows);
|
|
152
|
-
// console.log(rowsReceived.length)
|
|
153
|
-
// assert.equal(packet.ended, false);
|
|
154
|
-
// assert.equal(rowsReceived.length < totalRows, true);
|
|
155
|
-
// } catch(error){
|
|
156
|
-
// reject(error);
|
|
157
|
-
// }
|
|
158
|
-
// }
|
|
159
|
-
// };
|
|
160
|
-
// const startHandler = await res.start(listener);
|
|
161
|
-
// setTimeout(() => {
|
|
162
|
-
// startHandler.stop(true).catch(reject);
|
|
163
|
-
// }, 22);
|
|
164
|
-
// });
|
|
165
|
-
|
|
166
166
|
// await tryRunP("SQL Stream ensure the connection is never released (same pg_backend_pid is the same for subsequent) queries when using persistConnectionId", async (resolve, reject) => {
|
|
167
167
|
// const res = await db.sql!("SELECT pg_backend_pid()", {}, { returnType: "stream", persistConnectionId: true });
|
|
168
168
|
// const listener = async (packet: SocketSQLStreamPacket) => {
|