@powersync/service-module-postgres-storage 0.0.0-dev-20251030082344 → 0.0.0-dev-20251110113516
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 +21 -8
- package/dist/.tsbuildinfo +1 -1
- package/dist/@types/migrations/scripts/1756282360128-connection-reporting.d.ts +3 -0
- package/dist/@types/storage/PostgresReportStorage.d.ts +26 -0
- package/dist/@types/storage/PostgresStorageProvider.d.ts +1 -1
- package/dist/@types/storage/storage-index.d.ts +0 -1
- package/dist/@types/types/models/SdkReporting.d.ts +21 -0
- package/dist/@types/types/models/models-index.d.ts +1 -0
- package/dist/@types/{storage/PostgresTestStorageFactoryGenerator.d.ts → utils/test-utils.d.ts} +5 -3
- package/dist/@types/utils/utils-index.d.ts +1 -0
- package/dist/migrations/scripts/1756282360128-connection-reporting.js +107 -0
- package/dist/migrations/scripts/1756282360128-connection-reporting.js.map +1 -0
- package/dist/storage/PostgresReportStorage.js +315 -0
- package/dist/storage/PostgresReportStorage.js.map +1 -0
- package/dist/storage/PostgresStorageProvider.js +10 -1
- package/dist/storage/PostgresStorageProvider.js.map +1 -1
- package/dist/storage/storage-index.js +0 -1
- package/dist/storage/storage-index.js.map +1 -1
- package/dist/types/models/SdkReporting.js +17 -0
- package/dist/types/models/SdkReporting.js.map +1 -0
- package/dist/types/models/models-index.js +1 -0
- package/dist/types/models/models-index.js.map +1 -1
- package/dist/{storage/PostgresTestStorageFactoryGenerator.js → utils/test-utils.js} +22 -6
- package/dist/utils/test-utils.js.map +1 -0
- package/dist/utils/utils-index.js +1 -0
- package/dist/utils/utils-index.js.map +1 -1
- package/package.json +13 -13
- package/src/migrations/scripts/1756282360128-connection-reporting.ts +41 -0
- package/src/storage/PostgresReportStorage.ts +348 -0
- package/src/storage/PostgresStorageProvider.ts +13 -2
- package/src/storage/storage-index.ts +0 -1
- package/src/types/models/SdkReporting.ts +23 -0
- package/src/types/models/models-index.ts +1 -0
- package/src/{storage/PostgresTestStorageFactoryGenerator.ts → utils/test-utils.ts} +21 -5
- package/src/utils/utils-index.ts +1 -0
- package/test/src/__snapshots__/connection-report-storage.test.ts.snap +389 -0
- package/test/src/connection-report-storage.test.ts +232 -0
- package/test/src/util.ts +3 -6
- package/dist/storage/PostgresTestStorageFactoryGenerator.js.map +0 -1
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { storage } from '@powersync/service-core';
|
|
2
|
+
import * as pg_wire from '@powersync/service-jpgwire';
|
|
3
|
+
import { event_types } from '@powersync/service-types';
|
|
4
|
+
import * as lib_postgres from '@powersync/lib-service-postgres';
|
|
5
|
+
import { NormalizedPostgresStorageConfig } from '../types/types.js';
|
|
6
|
+
export type PostgresReportStorageOptions = {
|
|
7
|
+
config: NormalizedPostgresStorageConfig;
|
|
8
|
+
};
|
|
9
|
+
export declare class PostgresReportStorage implements storage.ReportStorage {
|
|
10
|
+
protected options: PostgresReportStorageOptions;
|
|
11
|
+
readonly db: lib_postgres.DatabaseClient;
|
|
12
|
+
constructor(options: PostgresReportStorageOptions);
|
|
13
|
+
private parseJsDate;
|
|
14
|
+
private mapListCurrentConnectionsResponse;
|
|
15
|
+
private listConnectionsQuery;
|
|
16
|
+
private updateTableFilter;
|
|
17
|
+
private clientsConnectionPagination;
|
|
18
|
+
reportClientConnection(data: event_types.ClientConnectionBucketData): Promise<void>;
|
|
19
|
+
reportClientDisconnection(data: event_types.ClientDisconnectionEventData): Promise<void>;
|
|
20
|
+
getConnectedClients(): Promise<event_types.ClientConnectionReportResponse>;
|
|
21
|
+
getClientConnectionReports(data: event_types.ClientConnectionReportRequest): Promise<event_types.ClientConnectionReportResponse>;
|
|
22
|
+
getClientConnections(data: event_types.ClientConnectionsRequest): Promise<event_types.PaginatedResponse<event_types.ClientConnection>>;
|
|
23
|
+
deleteOldConnectionData(data: event_types.DeleteOldConnectionData): Promise<void>;
|
|
24
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
25
|
+
prepareStatements(connection: pg_wire.PgConnection): Promise<void>;
|
|
26
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { storage } from '@powersync/service-core';
|
|
2
|
-
export declare class PostgresStorageProvider implements storage.
|
|
2
|
+
export declare class PostgresStorageProvider implements storage.StorageProvider {
|
|
3
3
|
get type(): "postgresql";
|
|
4
4
|
getStorage(options: storage.GetStorageOptions): Promise<storage.ActiveStorage>;
|
|
5
5
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as t from 'ts-codec';
|
|
2
|
+
export declare const Sdks: t.ObjectCodec<{
|
|
3
|
+
sdk: t.IdentityCodec<t.CodecType.String>;
|
|
4
|
+
clients: t.IdentityCodec<t.CodecType.Number>;
|
|
5
|
+
users: t.IdentityCodec<t.CodecType.Number>;
|
|
6
|
+
}>;
|
|
7
|
+
export type Sdks = t.Encoded<typeof Sdks>;
|
|
8
|
+
export declare const SdkReporting: t.ObjectCodec<{
|
|
9
|
+
users: t.Codec<bigint, string | number, string, t.CodecProps>;
|
|
10
|
+
sdks: t.Union<t.Codec<{
|
|
11
|
+
data: {
|
|
12
|
+
sdk: string;
|
|
13
|
+
clients: number;
|
|
14
|
+
users: number;
|
|
15
|
+
}[];
|
|
16
|
+
} | undefined, {
|
|
17
|
+
data: string;
|
|
18
|
+
} | undefined, string, t.CodecProps>, t.Codec<null, null, t.CodecType.Null, t.CodecProps>>;
|
|
19
|
+
}>;
|
|
20
|
+
export type SdkReporting = t.Encoded<typeof SdkReporting>;
|
|
21
|
+
export type SdkReportingDecoded = t.Decoded<typeof SdkReporting>;
|
package/dist/@types/{storage/PostgresTestStorageFactoryGenerator.d.ts → utils/test-utils.d.ts}
RENAMED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { framework, TestStorageOptions } from '@powersync/service-core';
|
|
2
2
|
import { PostgresMigrationAgent } from '../migrations/PostgresMigrationAgent.js';
|
|
3
3
|
import { PostgresStorageConfigDecoded } from '../types/types.js';
|
|
4
|
-
import {
|
|
4
|
+
import { PostgresReportStorage } from '../storage/PostgresReportStorage.js';
|
|
5
|
+
import { PostgresBucketStorageFactory } from '../storage/PostgresBucketStorageFactory.js';
|
|
5
6
|
export type PostgresTestStorageOptions = {
|
|
6
7
|
url: string;
|
|
7
8
|
/**
|
|
@@ -10,8 +11,9 @@ export type PostgresTestStorageOptions = {
|
|
|
10
11
|
*/
|
|
11
12
|
migrationAgent?: (config: PostgresStorageConfigDecoded) => PostgresMigrationAgent;
|
|
12
13
|
};
|
|
13
|
-
export declare
|
|
14
|
+
export declare function postgresTestSetup(factoryOptions: PostgresTestStorageOptions): {
|
|
15
|
+
reportFactory: (options?: TestStorageOptions) => Promise<PostgresReportStorage>;
|
|
14
16
|
factory: (options?: TestStorageOptions) => Promise<PostgresBucketStorageFactory>;
|
|
15
17
|
migrate: (direction: framework.migrations.Direction) => Promise<void>;
|
|
16
18
|
};
|
|
17
|
-
export declare
|
|
19
|
+
export declare function postgresTestStorageFactoryGenerator(factoryOptions: PostgresTestStorageOptions): (options?: TestStorageOptions) => Promise<PostgresBucketStorageFactory>;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
2
|
+
if (value !== null && value !== void 0) {
|
|
3
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
4
|
+
var dispose, inner;
|
|
5
|
+
if (async) {
|
|
6
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
7
|
+
dispose = value[Symbol.asyncDispose];
|
|
8
|
+
}
|
|
9
|
+
if (dispose === void 0) {
|
|
10
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
11
|
+
dispose = value[Symbol.dispose];
|
|
12
|
+
if (async) inner = dispose;
|
|
13
|
+
}
|
|
14
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
15
|
+
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
|
|
16
|
+
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
17
|
+
}
|
|
18
|
+
else if (async) {
|
|
19
|
+
env.stack.push({ async: true });
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
};
|
|
23
|
+
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
24
|
+
return function (env) {
|
|
25
|
+
function fail(e) {
|
|
26
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
27
|
+
env.hasError = true;
|
|
28
|
+
}
|
|
29
|
+
var r, s = 0;
|
|
30
|
+
function next() {
|
|
31
|
+
while (r = env.stack.pop()) {
|
|
32
|
+
try {
|
|
33
|
+
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
34
|
+
if (r.dispose) {
|
|
35
|
+
var result = r.dispose.call(r.value);
|
|
36
|
+
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
37
|
+
}
|
|
38
|
+
else s |= 1;
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
fail(e);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
45
|
+
if (env.hasError) throw env.error;
|
|
46
|
+
}
|
|
47
|
+
return next();
|
|
48
|
+
};
|
|
49
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
50
|
+
var e = new Error(message);
|
|
51
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
52
|
+
});
|
|
53
|
+
import { openMigrationDB } from '../migration-utils.js';
|
|
54
|
+
export const up = async (context) => {
|
|
55
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
56
|
+
try {
|
|
57
|
+
const { service_context: { configuration } } = context;
|
|
58
|
+
const client = __addDisposableResource(env_1, openMigrationDB(configuration.storage), true);
|
|
59
|
+
await client.transaction(async (db) => {
|
|
60
|
+
await db.sql `
|
|
61
|
+
CREATE TABLE IF NOT EXISTS connection_report_events (
|
|
62
|
+
id TEXT PRIMARY KEY,
|
|
63
|
+
user_agent TEXT NOT NULL,
|
|
64
|
+
client_id TEXT NOT NULL,
|
|
65
|
+
user_id TEXT NOT NULL,
|
|
66
|
+
sdk TEXT NOT NULL,
|
|
67
|
+
jwt_exp TIMESTAMP WITH TIME ZONE,
|
|
68
|
+
connected_at TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
69
|
+
disconnected_at TIMESTAMP WITH TIME ZONE
|
|
70
|
+
)
|
|
71
|
+
`.execute();
|
|
72
|
+
await db.sql `
|
|
73
|
+
CREATE INDEX IF NOT EXISTS sdk_list_index ON connection_report_events (connected_at, jwt_exp, disconnected_at)
|
|
74
|
+
`.execute();
|
|
75
|
+
await db.sql `CREATE INDEX IF NOT EXISTS sdk_user_id_index ON connection_report_events (user_id)`.execute();
|
|
76
|
+
await db.sql `CREATE INDEX IF NOT EXISTS sdk_client_id_index ON connection_report_events (client_id)`.execute();
|
|
77
|
+
await db.sql `CREATE INDEX IF NOT EXISTS sdk_index ON connection_report_events (sdk)`.execute();
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
catch (e_1) {
|
|
81
|
+
env_1.error = e_1;
|
|
82
|
+
env_1.hasError = true;
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
const result_1 = __disposeResources(env_1);
|
|
86
|
+
if (result_1)
|
|
87
|
+
await result_1;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
export const down = async (context) => {
|
|
91
|
+
const env_2 = { stack: [], error: void 0, hasError: false };
|
|
92
|
+
try {
|
|
93
|
+
const { service_context: { configuration } } = context;
|
|
94
|
+
const client = __addDisposableResource(env_2, openMigrationDB(configuration.storage), true);
|
|
95
|
+
await client.sql `DROP TABLE IF EXISTS connection_report_events`.execute();
|
|
96
|
+
}
|
|
97
|
+
catch (e_2) {
|
|
98
|
+
env_2.error = e_2;
|
|
99
|
+
env_2.hasError = true;
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
const result_2 = __disposeResources(env_2);
|
|
103
|
+
if (result_2)
|
|
104
|
+
await result_2;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
//# sourceMappingURL=1756282360128-connection-reporting.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"1756282360128-connection-reporting.js","sourceRoot":"","sources":["../../../src/migrations/scripts/1756282360128-connection-reporting.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,MAAM,CAAC,MAAM,EAAE,GAA0C,KAAK,EAAE,OAAO,EAAE,EAAE;;;QACzE,MAAM,EACJ,eAAe,EAAE,EAAE,aAAa,EAAE,EACnC,GAAG,OAAO,CAAC;QACZ,MAAY,MAAM,kCAAG,eAAe,CAAC,aAAa,CAAC,OAAO,CAAC,OAAA,CAAC;QAC5D,MAAM,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;YACpC,MAAM,EAAE,CAAC,GAAG,CAAA;;;;;;;;;;;KAWX,CAAC,OAAO,EAAE,CAAC;YAEZ,MAAM,EAAE,CAAC,GAAG,CAAA;;KAEX,CAAC,OAAO,EAAE,CAAC;YAEZ,MAAM,EAAE,CAAC,GAAG,CAAA,oFAAoF,CAAC,OAAO,EAAE,CAAC;YAE3G,MAAM,EAAE,CAAC,GAAG,CAAA,wFAAwF,CAAC,OAAO,EAAE,CAAC;YAE/G,MAAM,EAAE,CAAC,GAAG,CAAA,wEAAwE,CAAC,OAAO,EAAE,CAAC;QACjG,CAAC,CAAC,CAAC;;;;;;;;;;;CACJ,CAAC;AAEF,MAAM,CAAC,MAAM,IAAI,GAA0C,KAAK,EAAE,OAAO,EAAE,EAAE;;;QAC3E,MAAM,EACJ,eAAe,EAAE,EAAE,aAAa,EAAE,EACnC,GAAG,OAAO,CAAC;QACZ,MAAY,MAAM,kCAAG,eAAe,CAAC,aAAa,CAAC,OAAO,CAAC,OAAA,CAAC;QAC5D,MAAM,MAAM,CAAC,GAAG,CAAA,+CAA+C,CAAC,OAAO,EAAE,CAAC;;;;;;;;;;;CAC3E,CAAC"}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { v4 } from 'uuid';
|
|
2
|
+
import * as lib_postgres from '@powersync/lib-service-postgres';
|
|
3
|
+
import { SdkReporting } from '../types/models/SdkReporting.js';
|
|
4
|
+
import { toInteger } from 'ix/util/tointeger.js';
|
|
5
|
+
import { logger } from '@powersync/lib-services-framework';
|
|
6
|
+
import { getStorageApplicationName } from '../utils/application-name.js';
|
|
7
|
+
import { STORAGE_SCHEMA_NAME } from '../utils/db.js';
|
|
8
|
+
export class PostgresReportStorage {
|
|
9
|
+
options;
|
|
10
|
+
db;
|
|
11
|
+
constructor(options) {
|
|
12
|
+
this.options = options;
|
|
13
|
+
this.db = new lib_postgres.DatabaseClient({
|
|
14
|
+
config: options.config,
|
|
15
|
+
schema: STORAGE_SCHEMA_NAME,
|
|
16
|
+
applicationName: getStorageApplicationName()
|
|
17
|
+
});
|
|
18
|
+
this.db.registerListener({
|
|
19
|
+
connectionCreated: async (connection) => this.prepareStatements(connection)
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
parseJsDate(date) {
|
|
23
|
+
const year = date.getFullYear();
|
|
24
|
+
const month = date.getMonth();
|
|
25
|
+
const today = date.getDate();
|
|
26
|
+
const day = date.getDay();
|
|
27
|
+
return {
|
|
28
|
+
year,
|
|
29
|
+
month,
|
|
30
|
+
today,
|
|
31
|
+
day,
|
|
32
|
+
parsedDate: date
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
mapListCurrentConnectionsResponse(result) {
|
|
36
|
+
if (!result) {
|
|
37
|
+
return {
|
|
38
|
+
users: 0,
|
|
39
|
+
sdks: []
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
users: Number(result.users),
|
|
44
|
+
sdks: result.sdks?.data || []
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
async listConnectionsQuery() {
|
|
48
|
+
return await this.db.sql `
|
|
49
|
+
WITH
|
|
50
|
+
filtered AS (
|
|
51
|
+
SELECT
|
|
52
|
+
*
|
|
53
|
+
FROM
|
|
54
|
+
connection_report_events
|
|
55
|
+
WHERE
|
|
56
|
+
disconnected_at IS NULL
|
|
57
|
+
AND jwt_exp > NOW()
|
|
58
|
+
),
|
|
59
|
+
unique_users AS (
|
|
60
|
+
SELECT
|
|
61
|
+
COUNT(DISTINCT user_id) AS count
|
|
62
|
+
FROM
|
|
63
|
+
filtered
|
|
64
|
+
),
|
|
65
|
+
sdk_versions_array AS (
|
|
66
|
+
SELECT
|
|
67
|
+
sdk,
|
|
68
|
+
COUNT(DISTINCT client_id) AS clients,
|
|
69
|
+
COUNT(DISTINCT user_id) AS users
|
|
70
|
+
FROM
|
|
71
|
+
filtered
|
|
72
|
+
GROUP BY
|
|
73
|
+
sdk
|
|
74
|
+
)
|
|
75
|
+
SELECT
|
|
76
|
+
(
|
|
77
|
+
SELECT
|
|
78
|
+
COALESCE(count, 0)
|
|
79
|
+
FROM
|
|
80
|
+
unique_users
|
|
81
|
+
) AS users,
|
|
82
|
+
(
|
|
83
|
+
SELECT
|
|
84
|
+
JSON_AGG(ROW_TO_JSON(s))
|
|
85
|
+
FROM
|
|
86
|
+
sdk_versions_array s
|
|
87
|
+
) AS sdks;
|
|
88
|
+
`
|
|
89
|
+
.decoded(SdkReporting)
|
|
90
|
+
.first();
|
|
91
|
+
}
|
|
92
|
+
updateTableFilter() {
|
|
93
|
+
const { year, month, today } = this.parseJsDate(new Date());
|
|
94
|
+
const nextDay = today + 1;
|
|
95
|
+
return {
|
|
96
|
+
gte: new Date(year, month, today).toISOString(),
|
|
97
|
+
lt: new Date(year, month, nextDay).toISOString()
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
clientsConnectionPagination(params) {
|
|
101
|
+
const { cursor, limit, client_id, user_id, date_range } = params;
|
|
102
|
+
const queryLimit = limit || 100;
|
|
103
|
+
const queryParams = [];
|
|
104
|
+
let countQuery = `SELECT COUNT(*) AS total FROM connection_report_events`;
|
|
105
|
+
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`;
|
|
106
|
+
let intermediateQuery = '';
|
|
107
|
+
/** Create a user_id/ client_id filter is they exist */
|
|
108
|
+
if (client_id || user_id) {
|
|
109
|
+
if (client_id && !user_id) {
|
|
110
|
+
intermediateQuery += ` WHERE client_id = $1`;
|
|
111
|
+
queryParams.push({ type: 'varchar', value: client_id });
|
|
112
|
+
}
|
|
113
|
+
else if (!client_id && user_id) {
|
|
114
|
+
intermediateQuery += ` WHERE user_id = $1`;
|
|
115
|
+
queryParams.push({ type: 'varchar', value: user_id });
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
intermediateQuery += ' WHERE client_id = $1 AND user_id = $2';
|
|
119
|
+
queryParams.push({ type: 'varchar', value: client_id });
|
|
120
|
+
queryParams.push({ type: 'varchar', value: user_id });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/** Create a date range filter if it exists */
|
|
124
|
+
if (date_range) {
|
|
125
|
+
const { start, end } = date_range;
|
|
126
|
+
intermediateQuery +=
|
|
127
|
+
queryParams.length === 0
|
|
128
|
+
? ` WHERE connected_at >= $1 AND connected_at <= $2`
|
|
129
|
+
: ` AND connected_at >= $${queryParams.length + 1} AND connected_at <= $${queryParams.length + 2}`;
|
|
130
|
+
queryParams.push({ type: 1184, value: start.toISOString() });
|
|
131
|
+
queryParams.push({ type: 1184, value: end.toISOString() });
|
|
132
|
+
}
|
|
133
|
+
countQuery += intermediateQuery;
|
|
134
|
+
/** 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 */
|
|
135
|
+
if (cursor) {
|
|
136
|
+
intermediateQuery +=
|
|
137
|
+
queryParams.length === 0 ? ` WHERE connected_at < $1` : ` AND connected_at < $${queryParams.length + 1}`;
|
|
138
|
+
queryParams.push({ type: 1184, value: new Date(cursor).toISOString() });
|
|
139
|
+
}
|
|
140
|
+
/** Order in descending connected at range to match Mongo sort=-1*/
|
|
141
|
+
intermediateQuery += ` ORDER BY connected_at DESC`;
|
|
142
|
+
query += intermediateQuery;
|
|
143
|
+
return {
|
|
144
|
+
mainQuery: {
|
|
145
|
+
statement: query,
|
|
146
|
+
params: queryParams,
|
|
147
|
+
limit: queryLimit
|
|
148
|
+
},
|
|
149
|
+
countQuery: {
|
|
150
|
+
statement: countQuery,
|
|
151
|
+
params: queryParams
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
async reportClientConnection(data) {
|
|
156
|
+
const { sdk, connected_at, user_id, user_agent, jwt_exp, client_id } = data;
|
|
157
|
+
const connectIsoString = connected_at.toISOString();
|
|
158
|
+
const jwtExpIsoString = jwt_exp.toISOString();
|
|
159
|
+
const { gte, lt } = this.updateTableFilter();
|
|
160
|
+
const uuid = v4();
|
|
161
|
+
const result = await this.db.sql `
|
|
162
|
+
UPDATE connection_report_events
|
|
163
|
+
SET
|
|
164
|
+
connected_at = ${{ type: 1184, value: connectIsoString }},
|
|
165
|
+
sdk = ${{ type: 'varchar', value: sdk }},
|
|
166
|
+
user_agent = ${{ type: 'varchar', value: user_agent }},
|
|
167
|
+
jwt_exp = ${{ type: 1184, value: jwtExpIsoString }},
|
|
168
|
+
disconnected_at = NULL
|
|
169
|
+
WHERE
|
|
170
|
+
user_id = ${{ type: 'varchar', value: user_id }}
|
|
171
|
+
AND client_id = ${{ type: 'varchar', value: client_id }}
|
|
172
|
+
AND connected_at >= ${{ type: 1184, value: gte }}
|
|
173
|
+
AND connected_at < ${{ type: 1184, value: lt }};
|
|
174
|
+
`.execute();
|
|
175
|
+
if (result.results[1].status === 'UPDATE 0') {
|
|
176
|
+
await this.db.sql `
|
|
177
|
+
INSERT INTO
|
|
178
|
+
connection_report_events (
|
|
179
|
+
user_id,
|
|
180
|
+
client_id,
|
|
181
|
+
connected_at,
|
|
182
|
+
sdk,
|
|
183
|
+
user_agent,
|
|
184
|
+
jwt_exp,
|
|
185
|
+
id
|
|
186
|
+
)
|
|
187
|
+
VALUES
|
|
188
|
+
(
|
|
189
|
+
${{ type: 'varchar', value: user_id }},
|
|
190
|
+
${{ type: 'varchar', value: client_id }},
|
|
191
|
+
${{ type: 1184, value: connectIsoString }},
|
|
192
|
+
${{ type: 'varchar', value: sdk }},
|
|
193
|
+
${{ type: 'varchar', value: user_agent }},
|
|
194
|
+
${{ type: 1184, value: jwtExpIsoString }},
|
|
195
|
+
${{ type: 'varchar', value: uuid }}
|
|
196
|
+
)
|
|
197
|
+
`.execute();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
async reportClientDisconnection(data) {
|
|
201
|
+
const { user_id, client_id, disconnected_at, connected_at } = data;
|
|
202
|
+
const disconnectIsoString = disconnected_at.toISOString();
|
|
203
|
+
const connectIsoString = connected_at.toISOString();
|
|
204
|
+
await this.db.sql `
|
|
205
|
+
UPDATE connection_report_events
|
|
206
|
+
SET
|
|
207
|
+
disconnected_at = ${{ type: 1184, value: disconnectIsoString }},
|
|
208
|
+
jwt_exp = NULL
|
|
209
|
+
WHERE
|
|
210
|
+
user_id = ${{ type: 'varchar', value: user_id }}
|
|
211
|
+
AND client_id = ${{ type: 'varchar', value: client_id }}
|
|
212
|
+
AND connected_at = ${{ type: 1184, value: connectIsoString }}
|
|
213
|
+
`.execute();
|
|
214
|
+
}
|
|
215
|
+
async getConnectedClients() {
|
|
216
|
+
const result = await this.listConnectionsQuery();
|
|
217
|
+
return this.mapListCurrentConnectionsResponse(result);
|
|
218
|
+
}
|
|
219
|
+
async getClientConnectionReports(data) {
|
|
220
|
+
const { start, end } = data;
|
|
221
|
+
const result = await this.db.sql `
|
|
222
|
+
WITH
|
|
223
|
+
filtered AS (
|
|
224
|
+
SELECT
|
|
225
|
+
*
|
|
226
|
+
FROM
|
|
227
|
+
connection_report_events
|
|
228
|
+
WHERE
|
|
229
|
+
connected_at >= ${{ type: 1184, value: start.toISOString() }}
|
|
230
|
+
AND connected_at <= ${{ type: 1184, value: end.toISOString() }}
|
|
231
|
+
),
|
|
232
|
+
unique_users AS (
|
|
233
|
+
SELECT
|
|
234
|
+
COUNT(DISTINCT user_id) AS count
|
|
235
|
+
FROM
|
|
236
|
+
filtered
|
|
237
|
+
),
|
|
238
|
+
sdk_versions_array AS (
|
|
239
|
+
SELECT
|
|
240
|
+
sdk,
|
|
241
|
+
COUNT(DISTINCT client_id) AS clients,
|
|
242
|
+
COUNT(DISTINCT user_id) AS users
|
|
243
|
+
FROM
|
|
244
|
+
filtered
|
|
245
|
+
GROUP BY
|
|
246
|
+
sdk
|
|
247
|
+
)
|
|
248
|
+
SELECT
|
|
249
|
+
(
|
|
250
|
+
SELECT
|
|
251
|
+
COALESCE(count, 0)
|
|
252
|
+
FROM
|
|
253
|
+
unique_users
|
|
254
|
+
) AS users,
|
|
255
|
+
(
|
|
256
|
+
SELECT
|
|
257
|
+
JSON_AGG(ROW_TO_JSON(s))
|
|
258
|
+
FROM
|
|
259
|
+
sdk_versions_array s
|
|
260
|
+
) AS sdks;
|
|
261
|
+
`
|
|
262
|
+
.decoded(SdkReporting)
|
|
263
|
+
.first();
|
|
264
|
+
return this.mapListCurrentConnectionsResponse(result);
|
|
265
|
+
}
|
|
266
|
+
async getClientConnections(data) {
|
|
267
|
+
const limit = data.limit || 100;
|
|
268
|
+
const statement = this.clientsConnectionPagination(data);
|
|
269
|
+
const countResult = await this.db.queryRows(statement.countQuery);
|
|
270
|
+
const total = Number(countResult[0].total);
|
|
271
|
+
const result = await this.db.queryRows(statement.mainQuery);
|
|
272
|
+
const items = result.map((item) => ({
|
|
273
|
+
...item,
|
|
274
|
+
connected_at: new Date(item.connected_at),
|
|
275
|
+
disconnected_at: item.disconnected_at ? new Date(item.disconnected_at) : undefined,
|
|
276
|
+
jwt_exp: item.jwt_exp ? new Date(item.jwt_exp) : undefined
|
|
277
|
+
}));
|
|
278
|
+
const count = items.length;
|
|
279
|
+
return {
|
|
280
|
+
/** Setting the cursor to the connected at date of the last item in the list */
|
|
281
|
+
cursor: count === limit ? items[items.length - 1].connected_at.toISOString() : undefined,
|
|
282
|
+
count,
|
|
283
|
+
items,
|
|
284
|
+
more: count < total,
|
|
285
|
+
total
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
async deleteOldConnectionData(data) {
|
|
289
|
+
const { date } = data;
|
|
290
|
+
const result = await this.db.sql `
|
|
291
|
+
DELETE FROM connection_report_events
|
|
292
|
+
WHERE
|
|
293
|
+
connected_at < ${{ type: 1184, value: date.toISOString() }}
|
|
294
|
+
AND (
|
|
295
|
+
disconnected_at IS NOT NULL
|
|
296
|
+
OR (
|
|
297
|
+
jwt_exp < NOW()
|
|
298
|
+
AND disconnected_at IS NULL
|
|
299
|
+
)
|
|
300
|
+
);
|
|
301
|
+
`.execute();
|
|
302
|
+
const deletedRows = toInteger(result.results[1].status.split(' ')[1] || '0');
|
|
303
|
+
if (deletedRows > 0) {
|
|
304
|
+
logger.info(`TTL from ${date.toISOString()}: ${deletedRows} PostgresSQL rows have been removed from connection_report_events.`);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
async [Symbol.asyncDispose]() {
|
|
308
|
+
await this.db[Symbol.asyncDispose]();
|
|
309
|
+
}
|
|
310
|
+
async prepareStatements(connection) {
|
|
311
|
+
// It should be possible to prepare statements for some common operations here.
|
|
312
|
+
// This has not been implemented yet.
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
//# sourceMappingURL=PostgresReportStorage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PostgresReportStorage.js","sourceRoot":"","sources":["../../src/storage/PostgresReportStorage.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,EAAE,EAAE,MAAM,MAAM,CAAC;AAC1B,OAAO,KAAK,YAAY,MAAM,iCAAiC,CAAC;AAEhE,OAAO,EAAE,YAAY,EAAuB,MAAM,iCAAiC,CAAC;AACpF,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAC;AAC3D,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AACzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAOrD,MAAM,OAAO,qBAAqB;IAEV;IADb,EAAE,CAA8B;IACzC,YAAsB,OAAqC;QAArC,YAAO,GAAP,OAAO,CAA8B;QACzD,IAAI,CAAC,EAAE,GAAG,IAAI,YAAY,CAAC,cAAc,CAAC;YACxC,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,MAAM,EAAE,mBAAmB;YAC3B,eAAe,EAAE,yBAAyB,EAAE;SAC7C,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC;YACvB,iBAAiB,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC;SAC5E,CAAC,CAAC;IACL,CAAC;IAEO,WAAW,CAAC,IAAU;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAC1B,OAAO;YACL,IAAI;YACJ,KAAK;YACL,KAAK;YACL,GAAG;YACH,UAAU,EAAE,IAAI;SACjB,CAAC;IACJ,CAAC;IAEO,iCAAiC,CACvC,MAAkC;QAElC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO;gBACL,KAAK,EAAE,CAAC;gBACR,IAAI,EAAE,EAAE;aACT,CAAC;QACJ,CAAC;QACD,OAAO;YACL,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC;YAC3B,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE;SAC9B,CAAC;IACJ,CAAC;IACO,KAAK,CAAC,oBAAoB;QAChC,OAAO,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAwCvB;aACE,OAAO,CAAC,YAAY,CAAC;aACrB,KAAK,EAAE,CAAC;IACb,CAAC;IAEO,iBAAiB;QACvB,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;QAC5D,MAAM,OAAO,GAAG,KAAK,GAAG,CAAC,CAAC;QAC1B,OAAO;YACL,GAAG,EAAE,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,WAAW,EAAE;YAC/C,EAAE,EAAE,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,WAAW,EAAE;SACjD,CAAC;IACJ,CAAC;IAEO,2BAA2B,CAAC,MAA4C;QAI9E,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,CAAC;QACjE,MAAM,UAAU,GAAG,KAAK,IAAI,GAAG,CAAC;QAChC,MAAM,WAAW,GAA6B,EAAE,CAAC;QACjD,IAAI,UAAU,GAAG,wDAAwD,CAAC;QAC1E,IAAI,KAAK,GAAG,wMAAwM,CAAC;QACrN,IAAI,iBAAiB,GAAG,EAAE,CAAC;QAC3B,wDAAwD;QACxD,IAAI,SAAS,IAAI,OAAO,EAAE,CAAC;YACzB,IAAI,SAAS,IAAI,CAAC,OAAO,EAAE,CAAC;gBAC1B,iBAAiB,IAAI,uBAAuB,CAAC;gBAC7C,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;YAC1D,CAAC;iBAAM,IAAI,CAAC,SAAS,IAAI,OAAO,EAAE,CAAC;gBACjC,iBAAiB,IAAI,qBAAqB,CAAC;gBAC3C,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;YACxD,CAAC;iBAAM,CAAC;gBACN,iBAAiB,IAAI,wCAAwC,CAAC;gBAC9D,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAU,EAAE,CAAC,CAAC;gBACzD,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,OAAQ,EAAE,CAAC,CAAC;YACzD,CAAC;QACH,CAAC;QAED,8CAA8C;QAC9C,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,UAAU,CAAC;YAClC,iBAAiB;gBACf,WAAW,CAAC,MAAM,KAAK,CAAC;oBACtB,CAAC,CAAC,kDAAkD;oBACpD,CAAC,CAAC,yBAAyB,WAAW,CAAC,MAAM,GAAG,CAAC,yBAAyB,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvG,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;YAC7D,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC7D,CAAC;QAED,UAAU,IAAI,iBAAiB,CAAC;QAEhC,gLAAgL;QAChL,IAAI,MAAM,EAAE,CAAC;YACX,iBAAiB;gBACf,WAAW,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,wBAAwB,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3G,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC1E,CAAC;QAED,mEAAmE;QACnE,iBAAiB,IAAI,6BAA6B,CAAC;QACnD,KAAK,IAAI,iBAAiB,CAAC;QAC3B,OAAO;YACL,SAAS,EAAE;gBACT,SAAS,EAAE,KAAK;gBAChB,MAAM,EAAE,WAAW;gBACnB,KAAK,EAAE,UAAU;aAClB;YACD,UAAU,EAAE;gBACV,SAAS,EAAE,UAAU;gBACrB,MAAM,EAAE,WAAW;aACpB;SACF,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,sBAAsB,CAAC,IAA4C;QACvE,MAAM,EAAE,GAAG,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;QAC5E,MAAM,gBAAgB,GAAG,YAAY,CAAC,WAAW,EAAE,CAAC;QACpD,MAAM,eAAe,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;QAC9C,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC7C,MAAM,IAAI,GAAG,EAAE,EAAE,CAAC;QAClB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAA;;;yBAGX,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,gBAAgB,EAAE;gBAChD,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;uBACxB,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE;oBACzC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,eAAe,EAAE;;;oBAGtC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE;0BAC7B,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;8BACjC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE;6BAC3B,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE;KACjD,CAAC,OAAO,EAAE,CAAC;QACZ,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAC5C,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAA;;;;;;;;;;;;;cAaT,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE;cACnC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;cACrC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,gBAAgB,EAAE;cACvC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;cAC/B,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE;cACtC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,eAAe,EAAE;cACtC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE;;OAEvC,CAAC,OAAO,EAAE,CAAC;QACd,CAAC;IACH,CAAC;IACD,KAAK,CAAC,yBAAyB,CAAC,IAA8C;QAC5E,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;QACnE,MAAM,mBAAmB,GAAG,eAAe,CAAC,WAAW,EAAE,CAAC;QAC1D,MAAM,gBAAgB,GAAG,YAAY,CAAC,WAAW,EAAE,CAAC;QACpD,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAA;;;4BAGO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,mBAAmB,EAAE;;;oBAGlD,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE;0BAC7B,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;6BAClC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,gBAAgB,EAAE;KAC/D,CAAC,OAAO,EAAE,CAAC;IACd,CAAC;IACD,KAAK,CAAC,mBAAmB;QACvB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,oBAAoB,EAAE,CAAC;QACjD,OAAO,IAAI,CAAC,iCAAiC,CAAC,MAAM,CAAC,CAAC;IACxD,CAAC;IAED,KAAK,CAAC,0BAA0B,CAC9B,IAA+C;QAE/C,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QAC5B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAA;;;;;;;;8BAQN,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE,EAAE;kCACtC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,WAAW,EAAE,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA+BrE;aACE,OAAO,CAAC,YAAY,CAAC;aACrB,KAAK,EAAE,CAAC;QACX,OAAO,IAAI,CAAC,iCAAiC,CAAC,MAAM,CAAC,CAAC;IACxD,CAAC;IAED,KAAK,CAAC,oBAAoB,CACxB,IAA0C;QAE1C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,GAAG,CAAC;QAChC,MAAM,SAAS,GAAG,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAC,CAAC;QAEzD,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,SAAS,CAAoB,SAAS,CAAC,UAAU,CAAC,CAAC;QACrF,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAE3C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,SAAS,CAA2B,SAAS,CAAC,SAAS,CAAC,CAAC;QACtF,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAClC,GAAG,IAAI;YACP,YAAY,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC;YACzC,eAAe,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,SAAS;YAClF,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;SAC3D,CAAC,CAAC,CAAC;QACJ,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC;QAC3B,OAAO;YACL,+EAA+E;YAC/E,MAAM,EAAE,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS;YACxF,KAAK;YACL,KAAK;YACL,IAAI,EAAE,KAAK,GAAG,KAAK;YACnB,KAAK;SACN,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,uBAAuB,CAAC,IAAyC;QACrE,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;QACtB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAA;;;yBAGX,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE;;;;;;;;KAQ7D,CAAC,OAAO,EAAE,CAAC;QACZ,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC;QAC7E,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;YACpB,MAAM,CAAC,IAAI,CACT,YAAY,IAAI,CAAC,WAAW,EAAE,KAAK,WAAW,oEAAoE,CACnH,CAAC;QACJ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC;QACzB,MAAM,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,UAAgC;QACtD,+EAA+E;QAC/E,qCAAqC;IACvC,CAAC;CACF"}
|
|
@@ -3,6 +3,7 @@ import { logger } from '@powersync/lib-services-framework';
|
|
|
3
3
|
import { isPostgresStorageConfig, normalizePostgresStorageConfig, PostgresStorageConfig } from '../types/types.js';
|
|
4
4
|
import { dropTables } from '../utils/db.js';
|
|
5
5
|
import { PostgresBucketStorageFactory } from './PostgresBucketStorageFactory.js';
|
|
6
|
+
import { PostgresReportStorage } from './PostgresReportStorage.js';
|
|
6
7
|
export class PostgresStorageProvider {
|
|
7
8
|
get type() {
|
|
8
9
|
return lib_postgres.POSTGRES_CONNECTION_TYPE;
|
|
@@ -20,13 +21,21 @@ export class PostgresStorageProvider {
|
|
|
20
21
|
config: normalizedConfig,
|
|
21
22
|
slot_name_prefix: options.resolvedConfig.slot_name_prefix
|
|
22
23
|
});
|
|
24
|
+
const reportStorageFactory = new PostgresReportStorage({
|
|
25
|
+
config: normalizedConfig
|
|
26
|
+
});
|
|
23
27
|
return {
|
|
28
|
+
reportStorage: reportStorageFactory,
|
|
24
29
|
storage: storageFactory,
|
|
25
|
-
shutDown: async () =>
|
|
30
|
+
shutDown: async () => {
|
|
31
|
+
await storageFactory.db[Symbol.asyncDispose]();
|
|
32
|
+
await reportStorageFactory.db[Symbol.asyncDispose]();
|
|
33
|
+
},
|
|
26
34
|
tearDown: async () => {
|
|
27
35
|
logger.info(`Tearing down Postgres storage: ${normalizedConfig.database}...`);
|
|
28
36
|
await dropTables(storageFactory.db);
|
|
29
37
|
await storageFactory.db[Symbol.asyncDispose]();
|
|
38
|
+
await reportStorageFactory.db[Symbol.asyncDispose]();
|
|
30
39
|
return true;
|
|
31
40
|
}
|
|
32
41
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PostgresStorageProvider.js","sourceRoot":"","sources":["../../src/storage/PostgresStorageProvider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,YAAY,MAAM,iCAAiC,CAAC;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAC;AAG3D,OAAO,EAAE,uBAAuB,EAAE,8BAA8B,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AACnH,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"PostgresStorageProvider.js","sourceRoot":"","sources":["../../src/storage/PostgresStorageProvider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,YAAY,MAAM,iCAAiC,CAAC;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAC;AAG3D,OAAO,EAAE,uBAAuB,EAAE,8BAA8B,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AACnH,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,MAAM,OAAO,uBAAuB;IAClC,IAAI,IAAI;QACN,OAAO,YAAY,CAAC,wBAAwB,CAAC;IAC/C,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,OAAkC;QACjD,MAAM,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC;QAEnC,MAAM,EAAE,OAAO,EAAE,GAAG,cAAc,CAAC;QACnC,IAAI,CAAC,uBAAuB,CAAC,OAAO,CAAC,EAAE,CAAC;YACtC,gFAAgF;YAChF,MAAM,IAAI,KAAK,CACb,8DAA8D,OAAO,CAAC,IAAI,QAAQ,YAAY,CAAC,wBAAwB,EAAE,CAC1H,CAAC;QACJ,CAAC;QAED,MAAM,aAAa,GAAG,qBAAqB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC5D,MAAM,gBAAgB,GAAG,8BAA8B,CAAC,aAAa,CAAC,CAAC;QACvE,MAAM,cAAc,GAAG,IAAI,4BAA4B,CAAC;YACtD,MAAM,EAAE,gBAAgB;YACxB,gBAAgB,EAAE,OAAO,CAAC,cAAc,CAAC,gBAAgB;SAC1D,CAAC,CAAC;QAEH,MAAM,oBAAoB,GAAG,IAAI,qBAAqB,CAAC;YACrD,MAAM,EAAE,gBAAgB;SACzB,CAAC,CAAC;QAEH,OAAO;YACL,aAAa,EAAE,oBAAoB;YACnC,OAAO,EAAE,cAAc;YACvB,QAAQ,EAAE,KAAK,IAAI,EAAE;gBACnB,MAAM,cAAc,CAAC,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;gBAC/C,MAAM,oBAAoB,CAAC,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;YACvD,CAAC;YACD,QAAQ,EAAE,KAAK,IAAI,EAAE;gBACnB,MAAM,CAAC,IAAI,CAAC,kCAAkC,gBAAgB,CAAC,QAAQ,KAAK,CAAC,CAAC;gBAC9E,MAAM,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;gBACpC,MAAM,cAAc,CAAC,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;gBAC/C,MAAM,oBAAoB,CAAC,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;gBACrD,OAAO,IAAI,CAAC;YACd,CAAC;SAC8B,CAAC;IACpC,CAAC;CACF"}
|
|
@@ -2,5 +2,4 @@ export * from './PostgresBucketStorageFactory.js';
|
|
|
2
2
|
export * from './PostgresCompactor.js';
|
|
3
3
|
export * from './PostgresStorageProvider.js';
|
|
4
4
|
export * from './PostgresSyncRulesStorage.js';
|
|
5
|
-
export * from './PostgresTestStorageFactoryGenerator.js';
|
|
6
5
|
//# sourceMappingURL=storage-index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-index.js","sourceRoot":"","sources":["../../src/storage/storage-index.ts"],"names":[],"mappings":"AAAA,cAAc,mCAAmC,CAAC;AAClD,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,+BAA+B,CAAC
|
|
1
|
+
{"version":3,"file":"storage-index.js","sourceRoot":"","sources":["../../src/storage/storage-index.ts"],"names":[],"mappings":"AAAA,cAAc,mCAAmC,CAAC;AAClD,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,+BAA+B,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as t from 'ts-codec';
|
|
2
|
+
import { bigint, jsonb } from '../codecs.js';
|
|
3
|
+
export const Sdks = t.object({
|
|
4
|
+
sdk: t.string,
|
|
5
|
+
clients: t.number,
|
|
6
|
+
users: t.number
|
|
7
|
+
});
|
|
8
|
+
export const SdkReporting = t.object({
|
|
9
|
+
users: bigint,
|
|
10
|
+
sdks: t
|
|
11
|
+
.object({
|
|
12
|
+
data: jsonb(t.array(Sdks))
|
|
13
|
+
})
|
|
14
|
+
.optional()
|
|
15
|
+
.or(t.Null)
|
|
16
|
+
});
|
|
17
|
+
//# sourceMappingURL=SdkReporting.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SdkReporting.js","sourceRoot":"","sources":["../../../src/types/models/SdkReporting.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,GAAG,EAAE,CAAC,CAAC,MAAM;IACb,OAAO,EAAE,CAAC,CAAC,MAAM;IACjB,KAAK,EAAE,CAAC,CAAC,MAAM;CAChB,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,KAAK,EAAE,MAAM;IACb,IAAI,EAAE,CAAC;SACJ,MAAM,CAAC;QACN,IAAI,EAAE,KAAK,CAAS,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;KACnC,CAAC;SACD,QAAQ,EAAE;SACV,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;CACd,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"models-index.js","sourceRoot":"","sources":["../../../src/types/models/models-index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,mCAAmC,CAAC;AAClD,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"models-index.js","sourceRoot":"","sources":["../../../src/types/models/models-index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,mCAAmC,CAAC;AAClD,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC"}
|