@powersync/service-module-postgres-storage 0.10.12 → 0.10.14
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/CHANGELOG.md +32 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/@types/storage/PostgresReportStorage.d.ts +2 -0
- package/dist/@types/storage/batch/PostgresBucketBatch.d.ts +3 -0
- package/dist/@types/storage/batch/PostgresPersistedBatch.d.ts +6 -1
- package/dist/storage/PostgresReportStorage.js +84 -6
- package/dist/storage/PostgresReportStorage.js.map +1 -1
- package/dist/storage/batch/PostgresBucketBatch.js +30 -3
- package/dist/storage/batch/PostgresBucketBatch.js.map +1 -1
- package/dist/storage/batch/PostgresPersistedBatch.js +10 -0
- package/dist/storage/batch/PostgresPersistedBatch.js.map +1 -1
- package/package.json +12 -12
- package/src/storage/PostgresReportStorage.ts +97 -6
- package/src/storage/batch/PostgresBucketBatch.ts +36 -3
- package/src/storage/batch/PostgresPersistedBatch.ts +12 -0
- package/test/src/__snapshots__/connection-report-storage.test.ts.snap +264 -2
- package/test/src/connection-report-storage.test.ts +0 -1
|
@@ -9,6 +9,7 @@ import { toInteger } from 'ix/util/tointeger.js';
|
|
|
9
9
|
import { logger } from '@powersync/lib-services-framework';
|
|
10
10
|
import { getStorageApplicationName } from '../utils/application-name.js';
|
|
11
11
|
import { STORAGE_SCHEMA_NAME } from '../utils/db.js';
|
|
12
|
+
import { ClientConnectionResponse } from '@powersync/service-types/dist/reports.js';
|
|
12
13
|
|
|
13
14
|
export type PostgresReportStorageOptions = {
|
|
14
15
|
config: NormalizedPostgresStorageConfig;
|
|
@@ -29,10 +30,10 @@ export class PostgresReportStorage implements storage.ReportStorage {
|
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
private parseJsDate(date: Date) {
|
|
32
|
-
const year = date.
|
|
33
|
-
const month = date.
|
|
34
|
-
const today = date.
|
|
35
|
-
const day = date.
|
|
33
|
+
const year = date.getUTCFullYear();
|
|
34
|
+
const month = date.getUTCMonth();
|
|
35
|
+
const today = date.getUTCDate();
|
|
36
|
+
const day = date.getUTCDay();
|
|
36
37
|
return {
|
|
37
38
|
year,
|
|
38
39
|
month,
|
|
@@ -106,8 +107,70 @@ export class PostgresReportStorage implements storage.ReportStorage {
|
|
|
106
107
|
const { year, month, today } = this.parseJsDate(new Date());
|
|
107
108
|
const nextDay = today + 1;
|
|
108
109
|
return {
|
|
109
|
-
gte: new Date(year, month, today).toISOString(),
|
|
110
|
-
lt: new Date(year, month, nextDay).toISOString()
|
|
110
|
+
gte: new Date(Date.UTC(year, month, today)).toISOString(),
|
|
111
|
+
lt: new Date(Date.UTC(year, month, nextDay)).toISOString()
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private clientsConnectionPagination(params: event_types.ClientConnectionAnalyticsRequest): {
|
|
116
|
+
mainQuery: pg_wire.Statement;
|
|
117
|
+
countQuery: pg_wire.Statement;
|
|
118
|
+
} {
|
|
119
|
+
const { cursor, limit, client_id, user_id, date_range } = params;
|
|
120
|
+
const queryLimit = limit || 100;
|
|
121
|
+
const queryParams: pg_wire.StatementParam[] = [];
|
|
122
|
+
let countQuery = `SELECT COUNT(*) AS total FROM connection_report_events`;
|
|
123
|
+
let query = `SELECT id, user_id, client_id, user_agent, sdk, jwt_exp::text AS jwt_exp, disconnected_at, connected_at::text AS connected_at, disconnected_at::text AS disconnected_at FROM connection_report_events`;
|
|
124
|
+
let intermediateQuery = '';
|
|
125
|
+
/** Create a user_id/ client_id filter is they exist */
|
|
126
|
+
if (client_id != null || user_id) {
|
|
127
|
+
if (client_id && !user_id) {
|
|
128
|
+
intermediateQuery += ` WHERE client_id = $1`;
|
|
129
|
+
queryParams.push({ type: 'varchar', value: client_id });
|
|
130
|
+
} else if (!client_id && user_id != null) {
|
|
131
|
+
intermediateQuery += ` WHERE user_id = $1`;
|
|
132
|
+
queryParams.push({ type: 'varchar', value: user_id });
|
|
133
|
+
} else {
|
|
134
|
+
intermediateQuery += ' WHERE client_id = $1 AND user_id = $2';
|
|
135
|
+
queryParams.push({ type: 'varchar', value: client_id! });
|
|
136
|
+
queryParams.push({ type: 'varchar', value: user_id! });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** Create a date range filter if it exists */
|
|
141
|
+
if (date_range) {
|
|
142
|
+
const { start, end } = date_range;
|
|
143
|
+
intermediateQuery +=
|
|
144
|
+
queryParams.length === 0
|
|
145
|
+
? ` WHERE connected_at >= $1 AND connected_at <= $2`
|
|
146
|
+
: ` AND connected_at >= $${queryParams.length + 1} AND connected_at <= $${queryParams.length + 2}`;
|
|
147
|
+
queryParams.push({ type: 1184, value: start.toISOString() });
|
|
148
|
+
queryParams.push({ type: 1184, value: end.toISOString() });
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
countQuery += intermediateQuery;
|
|
152
|
+
|
|
153
|
+
/** Create a cursor filter if it exists. The cursor in postgres is the last item connection date, the id is an uuid so we cant use the same logic as in MongoReportStorage.ts */
|
|
154
|
+
if (cursor) {
|
|
155
|
+
intermediateQuery +=
|
|
156
|
+
queryParams.length === 0 ? ` WHERE connected_at < $1` : ` AND connected_at < $${queryParams.length + 1}`;
|
|
157
|
+
queryParams.push({ type: 1184, value: new Date(cursor).toISOString() });
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Order in descending connected at range to match Mongo sort=-1*/
|
|
161
|
+
intermediateQuery += ` ORDER BY connected_at DESC`;
|
|
162
|
+
query += intermediateQuery;
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
mainQuery: {
|
|
166
|
+
statement: query,
|
|
167
|
+
params: queryParams,
|
|
168
|
+
limit: queryLimit
|
|
169
|
+
},
|
|
170
|
+
countQuery: {
|
|
171
|
+
statement: countQuery,
|
|
172
|
+
params: queryParams
|
|
173
|
+
}
|
|
111
174
|
};
|
|
112
175
|
}
|
|
113
176
|
|
|
@@ -225,6 +288,34 @@ export class PostgresReportStorage implements storage.ReportStorage {
|
|
|
225
288
|
.first();
|
|
226
289
|
return this.mapListCurrentConnectionsResponse(result);
|
|
227
290
|
}
|
|
291
|
+
|
|
292
|
+
async getGeneralClientConnectionAnalytics(
|
|
293
|
+
data: event_types.ClientConnectionAnalyticsRequest
|
|
294
|
+
): Promise<event_types.PaginatedResponse<event_types.ClientConnection>> {
|
|
295
|
+
const limit = data.limit || 100;
|
|
296
|
+
const statement = this.clientsConnectionPagination(data);
|
|
297
|
+
|
|
298
|
+
const result = await this.db.queryRows<ClientConnectionResponse>(statement.mainQuery);
|
|
299
|
+
const items = result.map((item) => ({
|
|
300
|
+
...item,
|
|
301
|
+
/** JS Date conversion to match document schema used for Mongo storage */
|
|
302
|
+
connected_at: new Date(item.connected_at),
|
|
303
|
+
disconnected_at: item.disconnected_at ? new Date(item.disconnected_at) : undefined,
|
|
304
|
+
jwt_exp: item.jwt_exp ? new Date(item.jwt_exp) : undefined
|
|
305
|
+
}));
|
|
306
|
+
const count = items.length;
|
|
307
|
+
/** The returned total has been defaulted to 0 due to the overhead using documentCount from the mogo driver this is just to keep consistency with Mongo implementation.
|
|
308
|
+
* cursor.count has been deprecated.
|
|
309
|
+
* */
|
|
310
|
+
return {
|
|
311
|
+
items,
|
|
312
|
+
/** Setting the cursor to the connected at date of the last item in the list */
|
|
313
|
+
cursor: count === limit ? items[items.length - 1].connected_at.toISOString() : undefined,
|
|
314
|
+
count,
|
|
315
|
+
more: !(count !== limit)
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
|
|
228
319
|
async deleteOldConnectionData(data: event_types.DeleteOldConnectionData): Promise<void> {
|
|
229
320
|
const { date } = data;
|
|
230
321
|
const result = await this.db.sql`
|
|
@@ -77,6 +77,7 @@ export class PostgresBucketBatch
|
|
|
77
77
|
private lastWaitingLogThrottled = 0;
|
|
78
78
|
private markRecordUnavailable: BucketStorageMarkRecordUnavailable | undefined;
|
|
79
79
|
private needsActivation = true;
|
|
80
|
+
private clearedError = false;
|
|
80
81
|
|
|
81
82
|
constructor(protected options: PostgresBucketBatchOptions) {
|
|
82
83
|
super();
|
|
@@ -100,6 +101,10 @@ export class PostgresBucketBatch
|
|
|
100
101
|
return this.last_checkpoint_lsn;
|
|
101
102
|
}
|
|
102
103
|
|
|
104
|
+
get noCheckpointBeforeLsn() {
|
|
105
|
+
return this.no_checkpoint_before_lsn;
|
|
106
|
+
}
|
|
107
|
+
|
|
103
108
|
async [Symbol.asyncDispose]() {
|
|
104
109
|
super.clearListeners();
|
|
105
110
|
}
|
|
@@ -213,7 +218,10 @@ export class PostgresBucketBatch
|
|
|
213
218
|
});
|
|
214
219
|
}
|
|
215
220
|
}
|
|
216
|
-
await persistedBatch.flush(db);
|
|
221
|
+
const { flushedAny } = await persistedBatch.flush(db);
|
|
222
|
+
if (flushedAny) {
|
|
223
|
+
await this.clearError(db);
|
|
224
|
+
}
|
|
217
225
|
});
|
|
218
226
|
}
|
|
219
227
|
if (processedCount == 0) {
|
|
@@ -570,6 +578,7 @@ export class PostgresBucketBatch
|
|
|
570
578
|
|
|
571
579
|
// If set, we need to start a new transaction with this batch.
|
|
572
580
|
let resumeBatch: OperationBatch | null = null;
|
|
581
|
+
let didFlush = false;
|
|
573
582
|
|
|
574
583
|
// Now batch according to the sizes
|
|
575
584
|
// This is a single batch if storeCurrentData == false
|
|
@@ -654,7 +663,8 @@ export class PostgresBucketBatch
|
|
|
654
663
|
}
|
|
655
664
|
|
|
656
665
|
if (persistedBatch!.shouldFlushTransaction()) {
|
|
657
|
-
await persistedBatch!.flush(db);
|
|
666
|
+
const { flushedAny } = await persistedBatch!.flush(db);
|
|
667
|
+
didFlush ||= flushedAny;
|
|
658
668
|
// The operations stored in this batch will be processed in the `resumeBatch`
|
|
659
669
|
persistedBatch = null;
|
|
660
670
|
// Return the remaining entries for the next resume transaction
|
|
@@ -667,10 +677,15 @@ export class PostgresBucketBatch
|
|
|
667
677
|
* The operations were less than the max size if here. Flush now.
|
|
668
678
|
* `persistedBatch` will be `null` if the operations should be flushed in a new transaction.
|
|
669
679
|
*/
|
|
670
|
-
await persistedBatch.flush(db);
|
|
680
|
+
const { flushedAny } = await persistedBatch.flush(db);
|
|
681
|
+
didFlush ||= flushedAny;
|
|
671
682
|
}
|
|
672
683
|
}
|
|
673
684
|
|
|
685
|
+
if (didFlush) {
|
|
686
|
+
await this.clearError(db);
|
|
687
|
+
}
|
|
688
|
+
|
|
674
689
|
// Don't return empty batches
|
|
675
690
|
if (resumeBatch?.batch.length) {
|
|
676
691
|
return resumeBatch;
|
|
@@ -1006,6 +1021,24 @@ export class PostgresBucketBatch
|
|
|
1006
1021
|
}
|
|
1007
1022
|
}
|
|
1008
1023
|
|
|
1024
|
+
protected async clearError(
|
|
1025
|
+
db: lib_postgres.AbstractPostgresConnection | lib_postgres.DatabaseClient = this.db
|
|
1026
|
+
): Promise<void> {
|
|
1027
|
+
// No need to clear an error more than once per batch, since an error would always result in restarting the batch.
|
|
1028
|
+
if (this.clearedError) {
|
|
1029
|
+
return;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
await db.sql`
|
|
1033
|
+
UPDATE sync_rules
|
|
1034
|
+
SET
|
|
1035
|
+
last_fatal_error = ${{ type: 'varchar', value: null }}
|
|
1036
|
+
WHERE
|
|
1037
|
+
id = ${{ type: 'int4', value: this.group_id }}
|
|
1038
|
+
`.execute();
|
|
1039
|
+
this.clearedError = true;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1009
1042
|
private async getLastOpIdSequence(db: lib_postgres.AbstractPostgresConnection) {
|
|
1010
1043
|
// When no op_id has been generated, last_value = 1 and nextval() will be 1.
|
|
1011
1044
|
// To cater for this case, we check is_called, and default to 0 if no value has been generated.
|
|
@@ -236,6 +236,13 @@ export class PostgresPersistedBatch {
|
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
async flush(db: lib_postgres.WrappedConnection) {
|
|
239
|
+
const stats = {
|
|
240
|
+
bucketDataCount: this.bucketDataInserts.length,
|
|
241
|
+
parameterDataCount: this.parameterDataInserts.length,
|
|
242
|
+
currentDataCount: this.currentDataInserts.size + this.currentDataDeletes.length
|
|
243
|
+
};
|
|
244
|
+
const flushedAny = stats.bucketDataCount > 0 || stats.parameterDataCount > 0 || stats.currentDataCount > 0;
|
|
245
|
+
|
|
239
246
|
logger.info(
|
|
240
247
|
`powersync_${this.group_id} Flushed ${this.bucketDataInserts.length} + ${this.parameterDataInserts.length} + ${
|
|
241
248
|
this.currentDataInserts.size + this.currentDataDeletes.length
|
|
@@ -251,6 +258,11 @@ export class PostgresPersistedBatch {
|
|
|
251
258
|
this.currentDataDeletes = [];
|
|
252
259
|
this.currentDataInserts = new Map();
|
|
253
260
|
this.currentSize = 0;
|
|
261
|
+
|
|
262
|
+
return {
|
|
263
|
+
...stats,
|
|
264
|
+
flushedAny
|
|
265
|
+
};
|
|
254
266
|
}
|
|
255
267
|
|
|
256
268
|
protected async flushBucketData(db: lib_postgres.WrappedConnection) {
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
exports[`Connection report storage > Should create a connection event if its after a day 1`] = `
|
|
4
4
|
[
|
|
5
5
|
{
|
|
6
|
-
"client_id": "
|
|
6
|
+
"client_id": "client_one",
|
|
7
7
|
"sdk": "powersync-js/1.24.5",
|
|
8
8
|
"user_agent": "powersync-js/1.21.0 powersync-web Firefox/141 linux",
|
|
9
9
|
"user_id": "user_week",
|
|
10
10
|
},
|
|
11
11
|
{
|
|
12
|
-
"client_id": "
|
|
12
|
+
"client_id": "client_one",
|
|
13
13
|
"sdk": "powersync-js/1.24.5",
|
|
14
14
|
"user_agent": "powersync-js/1.21.0 powersync-web Firefox/141 linux",
|
|
15
15
|
"user_id": "user_week",
|
|
@@ -213,3 +213,265 @@ exports[`Report storage tests > Should show currently connected users 1`] = `
|
|
|
213
213
|
"users": 2,
|
|
214
214
|
}
|
|
215
215
|
`;
|
|
216
|
+
|
|
217
|
+
exports[`Report storage tests > Should show paginated response of all connections of specified client_id 1`] = `
|
|
218
|
+
{
|
|
219
|
+
"count": 1,
|
|
220
|
+
"cursor": undefined,
|
|
221
|
+
"items": [
|
|
222
|
+
{
|
|
223
|
+
"client_id": "client_two",
|
|
224
|
+
"id": "2",
|
|
225
|
+
"sdk": "powersync-js/1.21.1",
|
|
226
|
+
"user_agent": "powersync-js/1.21.0 powersync-web Chromium/138 linux",
|
|
227
|
+
"user_id": "user_two",
|
|
228
|
+
},
|
|
229
|
+
],
|
|
230
|
+
"more": false,
|
|
231
|
+
}
|
|
232
|
+
`;
|
|
233
|
+
|
|
234
|
+
exports[`Report storage tests > Should show paginated response of all connections with a limit 1`] = `
|
|
235
|
+
{
|
|
236
|
+
"count": 4,
|
|
237
|
+
"cursor": "<removed-for-snapshot>",
|
|
238
|
+
"items": [
|
|
239
|
+
{
|
|
240
|
+
"client_id": "client_one",
|
|
241
|
+
"id": "1",
|
|
242
|
+
"sdk": "powersync-dart/1.6.4",
|
|
243
|
+
"user_agent": "powersync-dart/1.6.4 Dart (flutter-web) Chrome/128 android",
|
|
244
|
+
"user_id": "user_one",
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
"client_id": "client_four",
|
|
248
|
+
"id": "4",
|
|
249
|
+
"sdk": "powersync-js/1.21.4",
|
|
250
|
+
"user_agent": "powersync-js/1.21.0 powersync-web Firefox/141 linux",
|
|
251
|
+
"user_id": "user_four",
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
"client_id": "client_two",
|
|
255
|
+
"id": "2",
|
|
256
|
+
"sdk": "powersync-js/1.21.1",
|
|
257
|
+
"user_agent": "powersync-js/1.21.0 powersync-web Chromium/138 linux",
|
|
258
|
+
"user_id": "user_two",
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
"client_id": "",
|
|
262
|
+
"id": "5",
|
|
263
|
+
"sdk": "unknown",
|
|
264
|
+
"user_agent": "Dart (flutter-web) Chrome/128 android",
|
|
265
|
+
"user_id": "user_one",
|
|
266
|
+
},
|
|
267
|
+
],
|
|
268
|
+
"more": true,
|
|
269
|
+
}
|
|
270
|
+
`;
|
|
271
|
+
|
|
272
|
+
exports[`Report storage tests > Should show paginated response of all connections with a limit 2`] = `
|
|
273
|
+
{
|
|
274
|
+
"count": 4,
|
|
275
|
+
"cursor": undefined,
|
|
276
|
+
"items": [
|
|
277
|
+
{
|
|
278
|
+
"client_id": "client_three",
|
|
279
|
+
"id": "3",
|
|
280
|
+
"sdk": "powersync-js/1.21.2",
|
|
281
|
+
"user_agent": "powersync-js/1.21.0 powersync-web Firefox/141 linux",
|
|
282
|
+
"user_id": "user_three",
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
"client_id": "client_one",
|
|
286
|
+
"id": "week",
|
|
287
|
+
"sdk": "powersync-js/1.24.5",
|
|
288
|
+
"user_agent": "powersync-js/1.21.0 powersync-web Firefox/141 linux",
|
|
289
|
+
"user_id": "user_week",
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
"client_id": "client_month",
|
|
293
|
+
"id": "month",
|
|
294
|
+
"sdk": "powersync-js/1.23.6",
|
|
295
|
+
"user_agent": "powersync-js/1.23.0 powersync-web Firefox/141 linux",
|
|
296
|
+
"user_id": "user_month",
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
"client_id": "client_expired",
|
|
300
|
+
"id": "expired",
|
|
301
|
+
"sdk": "powersync-js/1.23.7",
|
|
302
|
+
"user_agent": "powersync-js/1.23.0 powersync-web Firefox/141 linux",
|
|
303
|
+
"user_id": "user_expired",
|
|
304
|
+
},
|
|
305
|
+
],
|
|
306
|
+
"more": false,
|
|
307
|
+
}
|
|
308
|
+
`;
|
|
309
|
+
|
|
310
|
+
exports[`Report storage tests > Should show paginated response of all connections with a limit with date range 1`] = `
|
|
311
|
+
{
|
|
312
|
+
"count": 4,
|
|
313
|
+
"cursor": "<removed-for-snapshot>",
|
|
314
|
+
"items": [
|
|
315
|
+
{
|
|
316
|
+
"client_id": "client_two",
|
|
317
|
+
"id": "2",
|
|
318
|
+
"sdk": "powersync-js/1.21.1",
|
|
319
|
+
"user_agent": "powersync-js/1.21.0 powersync-web Chromium/138 linux",
|
|
320
|
+
"user_id": "user_two",
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
"client_id": "",
|
|
324
|
+
"id": "5",
|
|
325
|
+
"sdk": "unknown",
|
|
326
|
+
"user_agent": "Dart (flutter-web) Chrome/128 android",
|
|
327
|
+
"user_id": "user_one",
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
"client_id": "client_three",
|
|
331
|
+
"id": "3",
|
|
332
|
+
"sdk": "powersync-js/1.21.2",
|
|
333
|
+
"user_agent": "powersync-js/1.21.0 powersync-web Firefox/141 linux",
|
|
334
|
+
"user_id": "user_three",
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
"client_id": "client_one",
|
|
338
|
+
"id": "week",
|
|
339
|
+
"sdk": "powersync-js/1.24.5",
|
|
340
|
+
"user_agent": "powersync-js/1.21.0 powersync-web Firefox/141 linux",
|
|
341
|
+
"user_id": "user_week",
|
|
342
|
+
},
|
|
343
|
+
],
|
|
344
|
+
"more": true,
|
|
345
|
+
}
|
|
346
|
+
`;
|
|
347
|
+
|
|
348
|
+
exports[`Report storage tests > Should show paginated response of all connections with a limit with date range 2`] = `
|
|
349
|
+
{
|
|
350
|
+
"count": 2,
|
|
351
|
+
"cursor": undefined,
|
|
352
|
+
"items": [
|
|
353
|
+
{
|
|
354
|
+
"client_id": "client_two",
|
|
355
|
+
"id": "2",
|
|
356
|
+
"sdk": "powersync-js/1.21.1",
|
|
357
|
+
"user_agent": "powersync-js/1.21.0 powersync-web Chromium/138 linux",
|
|
358
|
+
"user_id": "user_two",
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
"client_id": "",
|
|
362
|
+
"id": "5",
|
|
363
|
+
"sdk": "unknown",
|
|
364
|
+
"user_agent": "Dart (flutter-web) Chrome/128 android",
|
|
365
|
+
"user_id": "user_one",
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
"client_id": "client_three",
|
|
369
|
+
"id": "3",
|
|
370
|
+
"sdk": "powersync-js/1.21.2",
|
|
371
|
+
"user_agent": "powersync-js/1.21.0 powersync-web Firefox/141 linux",
|
|
372
|
+
"user_id": "user_three",
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
"client_id": "client_one",
|
|
376
|
+
"id": "week",
|
|
377
|
+
"sdk": "powersync-js/1.24.5",
|
|
378
|
+
"user_agent": "powersync-js/1.21.0 powersync-web Firefox/141 linux",
|
|
379
|
+
"user_id": "user_week",
|
|
380
|
+
},
|
|
381
|
+
],
|
|
382
|
+
"more": false,
|
|
383
|
+
}
|
|
384
|
+
`;
|
|
385
|
+
|
|
386
|
+
exports[`Report storage tests > Should show paginated response of connections of specified user_id 1`] = `
|
|
387
|
+
{
|
|
388
|
+
"count": 2,
|
|
389
|
+
"cursor": undefined,
|
|
390
|
+
"items": [
|
|
391
|
+
{
|
|
392
|
+
"client_id": "client_one",
|
|
393
|
+
"id": "1",
|
|
394
|
+
"sdk": "powersync-dart/1.6.4",
|
|
395
|
+
"user_agent": "powersync-dart/1.6.4 Dart (flutter-web) Chrome/128 android",
|
|
396
|
+
"user_id": "user_one",
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
"client_id": "",
|
|
400
|
+
"id": "5",
|
|
401
|
+
"sdk": "unknown",
|
|
402
|
+
"user_agent": "Dart (flutter-web) Chrome/128 android",
|
|
403
|
+
"user_id": "user_one",
|
|
404
|
+
},
|
|
405
|
+
],
|
|
406
|
+
"more": false,
|
|
407
|
+
}
|
|
408
|
+
`;
|
|
409
|
+
|
|
410
|
+
exports[`Report storage tests > Should show paginated response of connections over a date range 1`] = `
|
|
411
|
+
{
|
|
412
|
+
"count": 6,
|
|
413
|
+
"cursor": undefined,
|
|
414
|
+
"items": [
|
|
415
|
+
{
|
|
416
|
+
"client_id": "client_one",
|
|
417
|
+
"id": "1",
|
|
418
|
+
"sdk": "powersync-dart/1.6.4",
|
|
419
|
+
"user_agent": "powersync-dart/1.6.4 Dart (flutter-web) Chrome/128 android",
|
|
420
|
+
"user_id": "user_one",
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
"client_id": "client_four",
|
|
424
|
+
"id": "4",
|
|
425
|
+
"sdk": "powersync-js/1.21.4",
|
|
426
|
+
"user_agent": "powersync-js/1.21.0 powersync-web Firefox/141 linux",
|
|
427
|
+
"user_id": "user_four",
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
"client_id": "client_two",
|
|
431
|
+
"id": "2",
|
|
432
|
+
"sdk": "powersync-js/1.21.1",
|
|
433
|
+
"user_agent": "powersync-js/1.21.0 powersync-web Chromium/138 linux",
|
|
434
|
+
"user_id": "user_two",
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
"client_id": "",
|
|
438
|
+
"id": "5",
|
|
439
|
+
"sdk": "unknown",
|
|
440
|
+
"user_agent": "Dart (flutter-web) Chrome/128 android",
|
|
441
|
+
"user_id": "user_one",
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
"client_id": "client_three",
|
|
445
|
+
"id": "3",
|
|
446
|
+
"sdk": "powersync-js/1.21.2",
|
|
447
|
+
"user_agent": "powersync-js/1.21.0 powersync-web Firefox/141 linux",
|
|
448
|
+
"user_id": "user_three",
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
"client_id": "client_one",
|
|
452
|
+
"id": "week",
|
|
453
|
+
"sdk": "powersync-js/1.24.5",
|
|
454
|
+
"user_agent": "powersync-js/1.21.0 powersync-web Firefox/141 linux",
|
|
455
|
+
"user_id": "user_week",
|
|
456
|
+
},
|
|
457
|
+
],
|
|
458
|
+
"more": false,
|
|
459
|
+
}
|
|
460
|
+
`;
|
|
461
|
+
|
|
462
|
+
exports[`Report storage tests > Should show paginated response of connections over a date range of specified client_id and user_id 1`] = `
|
|
463
|
+
{
|
|
464
|
+
"count": 1,
|
|
465
|
+
"cursor": undefined,
|
|
466
|
+
"items": [
|
|
467
|
+
{
|
|
468
|
+
"client_id": "client_one",
|
|
469
|
+
"id": "1",
|
|
470
|
+
"sdk": "powersync-dart/1.6.4",
|
|
471
|
+
"user_agent": "powersync-dart/1.6.4 Dart (flutter-web) Chrome/128 android",
|
|
472
|
+
"user_id": "user_one",
|
|
473
|
+
},
|
|
474
|
+
],
|
|
475
|
+
"more": false,
|
|
476
|
+
}
|
|
477
|
+
`;
|
|
@@ -185,7 +185,6 @@ describe('Connection report storage', async () => {
|
|
|
185
185
|
const sdk = await factory.db
|
|
186
186
|
.sql`SELECT * FROM connection_report_events WHERE user_id = ${{ type: 'varchar', value: userData.user_three.user_id }}`.rows<event_types.ClientConnection>();
|
|
187
187
|
expect(sdk).toHaveLength(1);
|
|
188
|
-
console.log(sdk[0]);
|
|
189
188
|
expect(new Date((sdk[0].disconnected_at! as unknown as DateTimeValue).iso8601Representation).toISOString()).toEqual(
|
|
190
189
|
disconnectAt.toISOString()
|
|
191
190
|
);
|