@mtcute/postgres 0.29.1 → 0.29.2

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/README.md CHANGED
@@ -35,9 +35,30 @@ console.log(`logged in as ${self.displayName}`)
35
35
  new PostgresStorage(pool, {
36
36
  // PostgreSQL schema to use for all tables (default: 'mtcute')
37
37
  schema: 'my_schema',
38
- // Whether to automatically close the client when the storage is destroyed (default: true)
38
+ // Whether to automatically close the client when the storage is destroyed (default: false)
39
39
  // Calls .end(), .release(), or .close() depending on what the client supports
40
40
  autoClose: true,
41
+ // Account tag for multi-account isolation within the same schema (default: 'default')
42
+ account: 'bot-1',
43
+ })
44
+ ```
45
+
46
+ ## Multi-account
47
+
48
+ Multiple clients can share the same database and schema by using different `account` tags.
49
+ Each account's data is fully isolated from others:
50
+
51
+ ```ts
52
+ const pool = new pg.Pool({ connectionString: 'postgres://localhost/mydb' })
53
+
54
+ const bot1 = new TelegramClient({
55
+ storage: new PostgresStorage(pool, { account: 'bot-1' }),
56
+ // ...
57
+ })
58
+
59
+ const bot2 = new TelegramClient({
60
+ storage: new PostgresStorage(pool, { account: 'bot-2' }),
61
+ // ...
41
62
  })
42
63
  ```
43
64
 
@@ -72,8 +93,8 @@ const poolClient = await pool.connect()
72
93
  const storage = new PostgresStorage(poolClient)
73
94
  ```
74
95
 
75
- > **Note:** By default, mtcute will automatically close the client (via `.end()`, `.release()`, or `.close()`)
76
- > when the storage is destroyed. Set `autoClose: false` if you want to manage the connection lifecycle yourself.
96
+ > **Note:** By default, mtcute does **not** close the client when the storage is destroyed.
97
+ > Set `autoClose: true` if you want the storage to call `.end()`, `.release()`, or `.close()` automatically.
77
98
 
78
99
  ## Database schema
79
100
 
package/driver.cjs CHANGED
@@ -9,16 +9,18 @@ const core = require("@mtcute/core");
9
9
  class PostgresStorageDriver extends core.BaseStorageDriver {
10
10
  client;
11
11
  schema;
12
+ account;
12
13
  _cleanup;
13
14
  _migrations = /* @__PURE__ */ new Map();
14
15
  _maxVersion = /* @__PURE__ */ new Map();
15
16
  _onLoadCallbacks = /* @__PURE__ */ new Set();
16
- _autoClose = true;
17
+ _autoClose = false;
17
18
  constructor(client, options) {
18
19
  super();
19
20
  this.client = client;
20
21
  this.schema = options?.schema ?? "mtcute";
21
- this._autoClose = options?.autoClose ?? true;
22
+ this.account = options?.account ?? "default";
23
+ this._autoClose = options?.autoClose ?? false;
22
24
  }
23
25
  /** Returns a schema-qualified table name, safe for interpolation into SQL */
24
26
  tableName(name) {
package/driver.d.cts CHANGED
@@ -23,13 +23,20 @@ export interface PostgresStorageDriverOptions {
23
23
  /**
24
24
  * Whether to automatically close the client when the driver is destroyed.
25
25
  *
26
- * @default true
26
+ * @default false
27
27
  */
28
28
  autoClose?: boolean;
29
+ /**
30
+ * Account tag used to isolate data when multiple clients share the same database and schema.
31
+ *
32
+ * @default 'default'
33
+ */
34
+ account?: string;
29
35
  }
30
36
  export declare class PostgresStorageDriver extends BaseStorageDriver {
31
37
  readonly client: PgClient;
32
38
  readonly schema: string;
39
+ readonly account: string;
33
40
  private _cleanup?;
34
41
  private _migrations;
35
42
  private _maxVersion;
package/driver.d.ts CHANGED
@@ -23,13 +23,20 @@ export interface PostgresStorageDriverOptions {
23
23
  /**
24
24
  * Whether to automatically close the client when the driver is destroyed.
25
25
  *
26
- * @default true
26
+ * @default false
27
27
  */
28
28
  autoClose?: boolean;
29
+ /**
30
+ * Account tag used to isolate data when multiple clients share the same database and schema.
31
+ *
32
+ * @default 'default'
33
+ */
34
+ account?: string;
29
35
  }
30
36
  export declare class PostgresStorageDriver extends BaseStorageDriver {
31
37
  readonly client: PgClient;
32
38
  readonly schema: string;
39
+ readonly account: string;
33
40
  private _cleanup?;
34
41
  private _migrations;
35
42
  private _maxVersion;
package/driver.js CHANGED
@@ -2,16 +2,18 @@ import { BaseStorageDriver } from "@mtcute/core";
2
2
  class PostgresStorageDriver extends BaseStorageDriver {
3
3
  client;
4
4
  schema;
5
+ account;
5
6
  _cleanup;
6
7
  _migrations = /* @__PURE__ */ new Map();
7
8
  _maxVersion = /* @__PURE__ */ new Map();
8
9
  _onLoadCallbacks = /* @__PURE__ */ new Set();
9
- _autoClose = true;
10
+ _autoClose = false;
10
11
  constructor(client, options) {
11
12
  super();
12
13
  this.client = client;
13
14
  this.schema = options?.schema ?? "mtcute";
14
- this._autoClose = options?.autoClose ?? true;
15
+ this.account = options?.account ?? "default";
16
+ this._autoClose = options?.autoClose ?? false;
15
17
  }
16
18
  /** Returns a schema-qualified table name, safe for interpolation into SQL */
17
19
  tableName(name) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mtcute/postgres",
3
3
  "type": "module",
4
- "version": "0.29.1",
4
+ "version": "0.29.2",
5
5
  "description": "PostgreSQL storage for mtcute",
6
6
  "license": "MIT",
7
7
  "dependencies": {
@@ -27,53 +27,71 @@ class PostgresAuthKeysRepository {
27
27
  );
28
28
  `);
29
29
  });
30
+ _driver.registerMigration("auth_keys", 2, async (client) => {
31
+ await client.query(`alter table ${this._authKeys} add column account text not null default 'default'`);
32
+ await client.query(`alter table ${this._authKeys} drop constraint auth_keys_pkey`);
33
+ await client.query(`alter table ${this._authKeys} add primary key (account, dc)`);
34
+ await client.query(`alter table ${this._tempAuthKeys} add column account text not null default 'default'`);
35
+ await client.query(`alter table ${this._tempAuthKeys} drop constraint temp_auth_keys_pkey`);
36
+ await client.query(`alter table ${this._tempAuthKeys} add primary key (account, dc, idx)`);
37
+ });
30
38
  }
31
39
  _authKeys;
32
40
  _tempAuthKeys;
41
+ get _account() {
42
+ return this._driver.account;
43
+ }
33
44
  async set(dc, key) {
34
45
  if (!key) {
35
- await this._driver.client.query(`delete from ${this._authKeys} where dc = $1`, [dc]);
46
+ await this._driver.client.query(
47
+ `delete from ${this._authKeys} where account = $1 and dc = $2`,
48
+ [this._account, dc]
49
+ );
36
50
  return;
37
51
  }
38
52
  await this._driver.client.query(
39
- `insert into ${this._authKeys} (dc, key) values ($1, $2) on conflict (dc) do update set key = $2`,
40
- [dc, key]
53
+ `insert into ${this._authKeys} (account, dc, key) values ($1, $2, $3)
54
+ on conflict (account, dc) do update set key = $3`,
55
+ [this._account, dc, key]
41
56
  );
42
57
  }
43
58
  async get(dc) {
44
- const res = await this._driver.client.query(`select key from ${this._authKeys} where dc = $1`, [dc]);
59
+ const res = await this._driver.client.query(
60
+ `select key from ${this._authKeys} where account = $1 and dc = $2`,
61
+ [this._account, dc]
62
+ );
45
63
  if (!res.rows[0]) return null;
46
64
  return new Uint8Array(res.rows[0].key);
47
65
  }
48
66
  async setTemp(dc, idx, key, expires) {
49
67
  if (!key) {
50
68
  await this._driver.client.query(
51
- `delete from ${this._tempAuthKeys} where dc = $1 and idx = $2`,
52
- [dc, idx]
69
+ `delete from ${this._tempAuthKeys} where account = $1 and dc = $2 and idx = $3`,
70
+ [this._account, dc, idx]
53
71
  );
54
72
  return;
55
73
  }
56
74
  await this._driver.client.query(
57
- `insert into ${this._tempAuthKeys} (dc, idx, key, expires) values ($1, $2, $3, $4)
58
- on conflict (dc, idx) do update set key = $3, expires = $4`,
59
- [dc, idx, key, expires]
75
+ `insert into ${this._tempAuthKeys} (account, dc, idx, key, expires) values ($1, $2, $3, $4, $5)
76
+ on conflict (account, dc, idx) do update set key = $4, expires = $5`,
77
+ [this._account, dc, idx, key, expires]
60
78
  );
61
79
  }
62
80
  async getTemp(dc, idx, now) {
63
81
  const res = await this._driver.client.query(
64
- `select key from ${this._tempAuthKeys} where dc = $1 and idx = $2 and expires > $3`,
65
- [dc, idx, now]
82
+ `select key from ${this._tempAuthKeys} where account = $1 and dc = $2 and idx = $3 and expires > $4`,
83
+ [this._account, dc, idx, now]
66
84
  );
67
85
  if (!res.rows[0]) return null;
68
86
  return new Uint8Array(res.rows[0].key);
69
87
  }
70
88
  async deleteByDc(dc) {
71
- await this._driver.client.query(`delete from ${this._authKeys} where dc = $1`, [dc]);
72
- await this._driver.client.query(`delete from ${this._tempAuthKeys} where dc = $1`, [dc]);
89
+ await this._driver.client.query(`delete from ${this._authKeys} where account = $1 and dc = $2`, [this._account, dc]);
90
+ await this._driver.client.query(`delete from ${this._tempAuthKeys} where account = $1 and dc = $2`, [this._account, dc]);
73
91
  }
74
92
  async deleteAll() {
75
- await this._driver.client.query(`delete from ${this._authKeys}`);
76
- await this._driver.client.query(`delete from ${this._tempAuthKeys}`);
93
+ await this._driver.client.query(`delete from ${this._authKeys} where account = $1`, [this._account]);
94
+ await this._driver.client.query(`delete from ${this._tempAuthKeys} where account = $1`, [this._account]);
77
95
  }
78
96
  }
79
97
  exports.PostgresAuthKeysRepository = PostgresAuthKeysRepository;
@@ -5,6 +5,7 @@ export declare class PostgresAuthKeysRepository implements IAuthKeysRepository {
5
5
  private _authKeys;
6
6
  private _tempAuthKeys;
7
7
  constructor(_driver: PostgresStorageDriver);
8
+ private get _account();
8
9
  set(dc: number, key: Uint8Array | null): Promise<void>;
9
10
  get(dc: number): Promise<Uint8Array | null>;
10
11
  setTemp(dc: number, idx: number, key: Uint8Array | null, expires: number): Promise<void>;
@@ -5,6 +5,7 @@ export declare class PostgresAuthKeysRepository implements IAuthKeysRepository {
5
5
  private _authKeys;
6
6
  private _tempAuthKeys;
7
7
  constructor(_driver: PostgresStorageDriver);
8
+ private get _account();
8
9
  set(dc: number, key: Uint8Array | null): Promise<void>;
9
10
  get(dc: number): Promise<Uint8Array | null>;
10
11
  setTemp(dc: number, idx: number, key: Uint8Array | null, expires: number): Promise<void>;
@@ -20,53 +20,71 @@ class PostgresAuthKeysRepository {
20
20
  );
21
21
  `);
22
22
  });
23
+ _driver.registerMigration("auth_keys", 2, async (client) => {
24
+ await client.query(`alter table ${this._authKeys} add column account text not null default 'default'`);
25
+ await client.query(`alter table ${this._authKeys} drop constraint auth_keys_pkey`);
26
+ await client.query(`alter table ${this._authKeys} add primary key (account, dc)`);
27
+ await client.query(`alter table ${this._tempAuthKeys} add column account text not null default 'default'`);
28
+ await client.query(`alter table ${this._tempAuthKeys} drop constraint temp_auth_keys_pkey`);
29
+ await client.query(`alter table ${this._tempAuthKeys} add primary key (account, dc, idx)`);
30
+ });
23
31
  }
24
32
  _authKeys;
25
33
  _tempAuthKeys;
34
+ get _account() {
35
+ return this._driver.account;
36
+ }
26
37
  async set(dc, key) {
27
38
  if (!key) {
28
- await this._driver.client.query(`delete from ${this._authKeys} where dc = $1`, [dc]);
39
+ await this._driver.client.query(
40
+ `delete from ${this._authKeys} where account = $1 and dc = $2`,
41
+ [this._account, dc]
42
+ );
29
43
  return;
30
44
  }
31
45
  await this._driver.client.query(
32
- `insert into ${this._authKeys} (dc, key) values ($1, $2) on conflict (dc) do update set key = $2`,
33
- [dc, key]
46
+ `insert into ${this._authKeys} (account, dc, key) values ($1, $2, $3)
47
+ on conflict (account, dc) do update set key = $3`,
48
+ [this._account, dc, key]
34
49
  );
35
50
  }
36
51
  async get(dc) {
37
- const res = await this._driver.client.query(`select key from ${this._authKeys} where dc = $1`, [dc]);
52
+ const res = await this._driver.client.query(
53
+ `select key from ${this._authKeys} where account = $1 and dc = $2`,
54
+ [this._account, dc]
55
+ );
38
56
  if (!res.rows[0]) return null;
39
57
  return new Uint8Array(res.rows[0].key);
40
58
  }
41
59
  async setTemp(dc, idx, key, expires) {
42
60
  if (!key) {
43
61
  await this._driver.client.query(
44
- `delete from ${this._tempAuthKeys} where dc = $1 and idx = $2`,
45
- [dc, idx]
62
+ `delete from ${this._tempAuthKeys} where account = $1 and dc = $2 and idx = $3`,
63
+ [this._account, dc, idx]
46
64
  );
47
65
  return;
48
66
  }
49
67
  await this._driver.client.query(
50
- `insert into ${this._tempAuthKeys} (dc, idx, key, expires) values ($1, $2, $3, $4)
51
- on conflict (dc, idx) do update set key = $3, expires = $4`,
52
- [dc, idx, key, expires]
68
+ `insert into ${this._tempAuthKeys} (account, dc, idx, key, expires) values ($1, $2, $3, $4, $5)
69
+ on conflict (account, dc, idx) do update set key = $4, expires = $5`,
70
+ [this._account, dc, idx, key, expires]
53
71
  );
54
72
  }
55
73
  async getTemp(dc, idx, now) {
56
74
  const res = await this._driver.client.query(
57
- `select key from ${this._tempAuthKeys} where dc = $1 and idx = $2 and expires > $3`,
58
- [dc, idx, now]
75
+ `select key from ${this._tempAuthKeys} where account = $1 and dc = $2 and idx = $3 and expires > $4`,
76
+ [this._account, dc, idx, now]
59
77
  );
60
78
  if (!res.rows[0]) return null;
61
79
  return new Uint8Array(res.rows[0].key);
62
80
  }
63
81
  async deleteByDc(dc) {
64
- await this._driver.client.query(`delete from ${this._authKeys} where dc = $1`, [dc]);
65
- await this._driver.client.query(`delete from ${this._tempAuthKeys} where dc = $1`, [dc]);
82
+ await this._driver.client.query(`delete from ${this._authKeys} where account = $1 and dc = $2`, [this._account, dc]);
83
+ await this._driver.client.query(`delete from ${this._tempAuthKeys} where account = $1 and dc = $2`, [this._account, dc]);
66
84
  }
67
85
  async deleteAll() {
68
- await this._driver.client.query(`delete from ${this._authKeys}`);
69
- await this._driver.client.query(`delete from ${this._tempAuthKeys}`);
86
+ await this._driver.client.query(`delete from ${this._authKeys} where account = $1`, [this._account]);
87
+ await this._driver.client.query(`delete from ${this._tempAuthKeys} where account = $1`, [this._account]);
70
88
  }
71
89
  }
72
90
  export {
package/repository/kv.cjs CHANGED
@@ -17,24 +17,39 @@ class PostgresKeyValueRepository {
17
17
  );
18
18
  `);
19
19
  });
20
+ _driver.registerMigration("kv", 2, async (client) => {
21
+ await client.query(`alter table ${this._table} add column account text not null default 'default'`);
22
+ await client.query(`alter table ${this._table} drop constraint key_value_pkey`);
23
+ await client.query(`alter table ${this._table} add primary key (account, key)`);
24
+ });
20
25
  }
21
26
  _table;
27
+ get _account() {
28
+ return this._driver.account;
29
+ }
22
30
  async set(key, value) {
23
31
  await this._driver.client.query(
24
- `insert into ${this._table} (key, value) values ($1, $2) on conflict (key) do update set value = $2`,
25
- [key, value]
32
+ `insert into ${this._table} (account, key, value) values ($1, $2, $3)
33
+ on conflict (account, key) do update set value = $3`,
34
+ [this._account, key, value]
26
35
  );
27
36
  }
28
37
  async get(key) {
29
- const res = await this._driver.client.query(`select value from ${this._table} where key = $1`, [key]);
38
+ const res = await this._driver.client.query(
39
+ `select value from ${this._table} where account = $1 and key = $2`,
40
+ [this._account, key]
41
+ );
30
42
  if (!res.rows[0]) return null;
31
43
  return new Uint8Array(res.rows[0].value);
32
44
  }
33
45
  async delete(key) {
34
- await this._driver.client.query(`delete from ${this._table} where key = $1`, [key]);
46
+ await this._driver.client.query(
47
+ `delete from ${this._table} where account = $1 and key = $2`,
48
+ [this._account, key]
49
+ );
35
50
  }
36
51
  async deleteAll() {
37
- await this._driver.client.query(`delete from ${this._table}`);
52
+ await this._driver.client.query(`delete from ${this._table} where account = $1`, [this._account]);
38
53
  }
39
54
  }
40
55
  exports.PostgresKeyValueRepository = PostgresKeyValueRepository;
@@ -4,6 +4,7 @@ export declare class PostgresKeyValueRepository implements IKeyValueRepository {
4
4
  readonly _driver: PostgresStorageDriver;
5
5
  private _table;
6
6
  constructor(_driver: PostgresStorageDriver);
7
+ private get _account();
7
8
  set(key: string, value: Uint8Array): Promise<void>;
8
9
  get(key: string): Promise<Uint8Array | null>;
9
10
  delete(key: string): Promise<void>;
@@ -4,6 +4,7 @@ export declare class PostgresKeyValueRepository implements IKeyValueRepository {
4
4
  readonly _driver: PostgresStorageDriver;
5
5
  private _table;
6
6
  constructor(_driver: PostgresStorageDriver);
7
+ private get _account();
7
8
  set(key: string, value: Uint8Array): Promise<void>;
8
9
  get(key: string): Promise<Uint8Array | null>;
9
10
  delete(key: string): Promise<void>;
package/repository/kv.js CHANGED
@@ -10,24 +10,39 @@ class PostgresKeyValueRepository {
10
10
  );
11
11
  `);
12
12
  });
13
+ _driver.registerMigration("kv", 2, async (client) => {
14
+ await client.query(`alter table ${this._table} add column account text not null default 'default'`);
15
+ await client.query(`alter table ${this._table} drop constraint key_value_pkey`);
16
+ await client.query(`alter table ${this._table} add primary key (account, key)`);
17
+ });
13
18
  }
14
19
  _table;
20
+ get _account() {
21
+ return this._driver.account;
22
+ }
15
23
  async set(key, value) {
16
24
  await this._driver.client.query(
17
- `insert into ${this._table} (key, value) values ($1, $2) on conflict (key) do update set value = $2`,
18
- [key, value]
25
+ `insert into ${this._table} (account, key, value) values ($1, $2, $3)
26
+ on conflict (account, key) do update set value = $3`,
27
+ [this._account, key, value]
19
28
  );
20
29
  }
21
30
  async get(key) {
22
- const res = await this._driver.client.query(`select value from ${this._table} where key = $1`, [key]);
31
+ const res = await this._driver.client.query(
32
+ `select value from ${this._table} where account = $1 and key = $2`,
33
+ [this._account, key]
34
+ );
23
35
  if (!res.rows[0]) return null;
24
36
  return new Uint8Array(res.rows[0].value);
25
37
  }
26
38
  async delete(key) {
27
- await this._driver.client.query(`delete from ${this._table} where key = $1`, [key]);
39
+ await this._driver.client.query(
40
+ `delete from ${this._table} where account = $1 and key = $2`,
41
+ [this._account, key]
42
+ );
28
43
  }
29
44
  async deleteAll() {
30
- await this._driver.client.query(`delete from ${this._table}`);
45
+ await this._driver.client.query(`delete from ${this._table} where account = $1`, [this._account]);
31
46
  }
32
47
  }
33
48
  export {
@@ -38,12 +38,22 @@ class PostgresPeersRepository {
38
38
  create index if not exists idx_peers_phone on ${this._table} (phone);
39
39
  `);
40
40
  });
41
+ _driver.registerMigration("peers", 2, async (client) => {
42
+ await client.query(`alter table ${this._table} add column account text not null default 'default'`);
43
+ await client.query(`alter table ${this._table} drop constraint peers_pkey`);
44
+ await client.query(`alter table ${this._table} add primary key (account, id)`);
45
+ await client.query(`drop index if exists ${_driver.tableName("idx_peers_phone")}`);
46
+ await client.query(`create index idx_peers_phone on ${this._table} (account, phone)`);
47
+ });
41
48
  _driver.onLoad(() => {
42
49
  this._loaded = true;
43
50
  });
44
51
  }
45
52
  _loaded = false;
46
53
  _table;
54
+ get _account() {
55
+ return this._driver.account;
56
+ }
47
57
  _ensureLoaded() {
48
58
  if (!this._loaded) {
49
59
  throw new core.MtcuteError("Peers repository is not loaded. Have you called client.start() (or similar)?");
@@ -51,11 +61,12 @@ class PostgresPeersRepository {
51
61
  }
52
62
  async store(peer) {
53
63
  await this._driver.client.query(
54
- `insert into ${this._table} (id, hash, is_min, usernames, updated, phone, complete)
55
- values ($1, $2, $3, $4, $5, $6, $7)
56
- on conflict (id) do update set
57
- hash = $2, is_min = $3, usernames = $4, updated = $5, phone = $6, complete = $7`,
64
+ `insert into ${this._table} (account, id, hash, is_min, usernames, updated, phone, complete)
65
+ values ($1, $2, $3, $4, $5, $6, $7, $8)
66
+ on conflict (account, id) do update set
67
+ hash = $3, is_min = $4, usernames = $5, updated = $6, phone = $7, complete = $8`,
58
68
  [
69
+ this._account,
59
70
  peer.id,
60
71
  peer.accessHash,
61
72
  peer.isMin,
@@ -68,15 +79,18 @@ class PostgresPeersRepository {
68
79
  }
69
80
  async getById(id) {
70
81
  this._ensureLoaded();
71
- const res = await this._driver.client.query(`select * from ${this._table} where id = $1`, [id]);
82
+ const res = await this._driver.client.query(
83
+ `select * from ${this._table} where account = $1 and id = $2`,
84
+ [this._account, id]
85
+ );
72
86
  if (!res.rows[0]) return null;
73
87
  return mapPeerDto(res.rows[0]);
74
88
  }
75
89
  async getByUsername(username) {
76
90
  this._ensureLoaded();
77
91
  const res = await this._driver.client.query(
78
- `select * from ${this._table} where usernames ? $1 and is_min = false`,
79
- [username]
92
+ `select * from ${this._table} where account = $1 and usernames ? $2 and is_min = false`,
93
+ [this._account, username]
80
94
  );
81
95
  if (!res.rows[0]) return null;
82
96
  return mapPeerDto(res.rows[0]);
@@ -84,14 +98,14 @@ class PostgresPeersRepository {
84
98
  async getByPhone(phone) {
85
99
  this._ensureLoaded();
86
100
  const res = await this._driver.client.query(
87
- `select * from ${this._table} where phone = $1 and is_min = false`,
88
- [phone]
101
+ `select * from ${this._table} where account = $1 and phone = $2 and is_min = false`,
102
+ [this._account, phone]
89
103
  );
90
104
  if (!res.rows[0]) return null;
91
105
  return mapPeerDto(res.rows[0]);
92
106
  }
93
107
  async deleteAll() {
94
- await this._driver.client.query(`delete from ${this._table}`);
108
+ await this._driver.client.query(`delete from ${this._table} where account = $1`, [this._account]);
95
109
  }
96
110
  }
97
111
  exports.PostgresPeersRepository = PostgresPeersRepository;
@@ -5,6 +5,7 @@ export declare class PostgresPeersRepository implements IPeersRepository {
5
5
  private _loaded;
6
6
  private _table;
7
7
  constructor(_driver: PostgresStorageDriver);
8
+ private get _account();
8
9
  private _ensureLoaded;
9
10
  store(peer: IPeersRepository.PeerInfo): Promise<void>;
10
11
  getById(id: number): Promise<IPeersRepository.PeerInfo | null>;
@@ -5,6 +5,7 @@ export declare class PostgresPeersRepository implements IPeersRepository {
5
5
  private _loaded;
6
6
  private _table;
7
7
  constructor(_driver: PostgresStorageDriver);
8
+ private get _account();
8
9
  private _ensureLoaded;
9
10
  store(peer: IPeersRepository.PeerInfo): Promise<void>;
10
11
  getById(id: number): Promise<IPeersRepository.PeerInfo | null>;
@@ -31,12 +31,22 @@ class PostgresPeersRepository {
31
31
  create index if not exists idx_peers_phone on ${this._table} (phone);
32
32
  `);
33
33
  });
34
+ _driver.registerMigration("peers", 2, async (client) => {
35
+ await client.query(`alter table ${this._table} add column account text not null default 'default'`);
36
+ await client.query(`alter table ${this._table} drop constraint peers_pkey`);
37
+ await client.query(`alter table ${this._table} add primary key (account, id)`);
38
+ await client.query(`drop index if exists ${_driver.tableName("idx_peers_phone")}`);
39
+ await client.query(`create index idx_peers_phone on ${this._table} (account, phone)`);
40
+ });
34
41
  _driver.onLoad(() => {
35
42
  this._loaded = true;
36
43
  });
37
44
  }
38
45
  _loaded = false;
39
46
  _table;
47
+ get _account() {
48
+ return this._driver.account;
49
+ }
40
50
  _ensureLoaded() {
41
51
  if (!this._loaded) {
42
52
  throw new MtcuteError("Peers repository is not loaded. Have you called client.start() (or similar)?");
@@ -44,11 +54,12 @@ class PostgresPeersRepository {
44
54
  }
45
55
  async store(peer) {
46
56
  await this._driver.client.query(
47
- `insert into ${this._table} (id, hash, is_min, usernames, updated, phone, complete)
48
- values ($1, $2, $3, $4, $5, $6, $7)
49
- on conflict (id) do update set
50
- hash = $2, is_min = $3, usernames = $4, updated = $5, phone = $6, complete = $7`,
57
+ `insert into ${this._table} (account, id, hash, is_min, usernames, updated, phone, complete)
58
+ values ($1, $2, $3, $4, $5, $6, $7, $8)
59
+ on conflict (account, id) do update set
60
+ hash = $3, is_min = $4, usernames = $5, updated = $6, phone = $7, complete = $8`,
51
61
  [
62
+ this._account,
52
63
  peer.id,
53
64
  peer.accessHash,
54
65
  peer.isMin,
@@ -61,15 +72,18 @@ class PostgresPeersRepository {
61
72
  }
62
73
  async getById(id) {
63
74
  this._ensureLoaded();
64
- const res = await this._driver.client.query(`select * from ${this._table} where id = $1`, [id]);
75
+ const res = await this._driver.client.query(
76
+ `select * from ${this._table} where account = $1 and id = $2`,
77
+ [this._account, id]
78
+ );
65
79
  if (!res.rows[0]) return null;
66
80
  return mapPeerDto(res.rows[0]);
67
81
  }
68
82
  async getByUsername(username) {
69
83
  this._ensureLoaded();
70
84
  const res = await this._driver.client.query(
71
- `select * from ${this._table} where usernames ? $1 and is_min = false`,
72
- [username]
85
+ `select * from ${this._table} where account = $1 and usernames ? $2 and is_min = false`,
86
+ [this._account, username]
73
87
  );
74
88
  if (!res.rows[0]) return null;
75
89
  return mapPeerDto(res.rows[0]);
@@ -77,14 +91,14 @@ class PostgresPeersRepository {
77
91
  async getByPhone(phone) {
78
92
  this._ensureLoaded();
79
93
  const res = await this._driver.client.query(
80
- `select * from ${this._table} where phone = $1 and is_min = false`,
81
- [phone]
94
+ `select * from ${this._table} where account = $1 and phone = $2 and is_min = false`,
95
+ [this._account, phone]
82
96
  );
83
97
  if (!res.rows[0]) return null;
84
98
  return mapPeerDto(res.rows[0]);
85
99
  }
86
100
  async deleteAll() {
87
- await this._driver.client.query(`delete from ${this._table}`);
101
+ await this._driver.client.query(`delete from ${this._table} where account = $1`, [this._account]);
88
102
  }
89
103
  }
90
104
  export {
@@ -21,18 +21,28 @@ class PostgresRefMessagesRepository {
21
21
  await client.query(`create index if not exists idx_message_refs_peer on ${this._table} (peer_id);`);
22
22
  await client.query(`create index if not exists idx_message_refs on ${this._table} (chat_id, msg_id);`);
23
23
  });
24
+ _driver.registerMigration("ref_messages", 2, async (client) => {
25
+ await client.query(`alter table ${this._table} add column account text not null default 'default'`);
26
+ await client.query(`drop index if exists ${_driver.tableName("idx_message_refs_peer")}`);
27
+ await client.query(`drop index if exists ${_driver.tableName("idx_message_refs")}`);
28
+ await client.query(`create index idx_message_refs_peer on ${this._table} (account, peer_id)`);
29
+ await client.query(`create index idx_message_refs on ${this._table} (account, chat_id, msg_id)`);
30
+ });
24
31
  }
25
32
  _table;
33
+ get _account() {
34
+ return this._driver.account;
35
+ }
26
36
  async store(peerId, chatId, msgId) {
27
37
  await this._driver.client.query(
28
- `insert into ${this._table} (peer_id, chat_id, msg_id) values ($1, $2, $3)`,
29
- [peerId, chatId, msgId]
38
+ `insert into ${this._table} (account, peer_id, chat_id, msg_id) values ($1, $2, $3, $4)`,
39
+ [this._account, peerId, chatId, msgId]
30
40
  );
31
41
  }
32
42
  async getByPeer(peerId) {
33
43
  const res = await this._driver.client.query(
34
- `select chat_id, msg_id from ${this._table} where peer_id = $1 limit 1`,
35
- [peerId]
44
+ `select chat_id, msg_id from ${this._table} where account = $1 and peer_id = $2 limit 1`,
45
+ [this._account, peerId]
36
46
  );
37
47
  if (!res.rows[0]) return null;
38
48
  const row = res.rows[0];
@@ -41,15 +51,18 @@ class PostgresRefMessagesRepository {
41
51
  async delete(chatId, msgIds) {
42
52
  if (msgIds.length === 0) return;
43
53
  await this._driver.client.query(
44
- `delete from ${this._table} where chat_id = $1 and msg_id = any($2)`,
45
- [chatId, msgIds]
54
+ `delete from ${this._table} where account = $1 and chat_id = $2 and msg_id = any($3)`,
55
+ [this._account, chatId, msgIds]
46
56
  );
47
57
  }
48
58
  async deleteByPeer(peerId) {
49
- await this._driver.client.query(`delete from ${this._table} where peer_id = $1`, [peerId]);
59
+ await this._driver.client.query(
60
+ `delete from ${this._table} where account = $1 and peer_id = $2`,
61
+ [this._account, peerId]
62
+ );
50
63
  }
51
64
  async deleteAll() {
52
- await this._driver.client.query(`delete from ${this._table}`);
65
+ await this._driver.client.query(`delete from ${this._table} where account = $1`, [this._account]);
53
66
  }
54
67
  }
55
68
  exports.PostgresRefMessagesRepository = PostgresRefMessagesRepository;
@@ -4,6 +4,7 @@ export declare class PostgresRefMessagesRepository implements IReferenceMessages
4
4
  readonly _driver: PostgresStorageDriver;
5
5
  private _table;
6
6
  constructor(_driver: PostgresStorageDriver);
7
+ private get _account();
7
8
  store(peerId: number, chatId: number, msgId: number): Promise<void>;
8
9
  getByPeer(peerId: number): Promise<[number, number] | null>;
9
10
  delete(chatId: number, msgIds: number[]): Promise<void>;
@@ -4,6 +4,7 @@ export declare class PostgresRefMessagesRepository implements IReferenceMessages
4
4
  readonly _driver: PostgresStorageDriver;
5
5
  private _table;
6
6
  constructor(_driver: PostgresStorageDriver);
7
+ private get _account();
7
8
  store(peerId: number, chatId: number, msgId: number): Promise<void>;
8
9
  getByPeer(peerId: number): Promise<[number, number] | null>;
9
10
  delete(chatId: number, msgIds: number[]): Promise<void>;
@@ -14,18 +14,28 @@ class PostgresRefMessagesRepository {
14
14
  await client.query(`create index if not exists idx_message_refs_peer on ${this._table} (peer_id);`);
15
15
  await client.query(`create index if not exists idx_message_refs on ${this._table} (chat_id, msg_id);`);
16
16
  });
17
+ _driver.registerMigration("ref_messages", 2, async (client) => {
18
+ await client.query(`alter table ${this._table} add column account text not null default 'default'`);
19
+ await client.query(`drop index if exists ${_driver.tableName("idx_message_refs_peer")}`);
20
+ await client.query(`drop index if exists ${_driver.tableName("idx_message_refs")}`);
21
+ await client.query(`create index idx_message_refs_peer on ${this._table} (account, peer_id)`);
22
+ await client.query(`create index idx_message_refs on ${this._table} (account, chat_id, msg_id)`);
23
+ });
17
24
  }
18
25
  _table;
26
+ get _account() {
27
+ return this._driver.account;
28
+ }
19
29
  async store(peerId, chatId, msgId) {
20
30
  await this._driver.client.query(
21
- `insert into ${this._table} (peer_id, chat_id, msg_id) values ($1, $2, $3)`,
22
- [peerId, chatId, msgId]
31
+ `insert into ${this._table} (account, peer_id, chat_id, msg_id) values ($1, $2, $3, $4)`,
32
+ [this._account, peerId, chatId, msgId]
23
33
  );
24
34
  }
25
35
  async getByPeer(peerId) {
26
36
  const res = await this._driver.client.query(
27
- `select chat_id, msg_id from ${this._table} where peer_id = $1 limit 1`,
28
- [peerId]
37
+ `select chat_id, msg_id from ${this._table} where account = $1 and peer_id = $2 limit 1`,
38
+ [this._account, peerId]
29
39
  );
30
40
  if (!res.rows[0]) return null;
31
41
  const row = res.rows[0];
@@ -34,15 +44,18 @@ class PostgresRefMessagesRepository {
34
44
  async delete(chatId, msgIds) {
35
45
  if (msgIds.length === 0) return;
36
46
  await this._driver.client.query(
37
- `delete from ${this._table} where chat_id = $1 and msg_id = any($2)`,
38
- [chatId, msgIds]
47
+ `delete from ${this._table} where account = $1 and chat_id = $2 and msg_id = any($3)`,
48
+ [this._account, chatId, msgIds]
39
49
  );
40
50
  }
41
51
  async deleteByPeer(peerId) {
42
- await this._driver.client.query(`delete from ${this._table} where peer_id = $1`, [peerId]);
52
+ await this._driver.client.query(
53
+ `delete from ${this._table} where account = $1 and peer_id = $2`,
54
+ [this._account, peerId]
55
+ );
43
56
  }
44
57
  async deleteAll() {
45
- await this._driver.client.query(`delete from ${this._table}`);
58
+ await this._driver.client.query(`delete from ${this._table} where account = $1`, [this._account]);
46
59
  }
47
60
  }
48
61
  export {