@squiz/db-lib 1.2.1-alpha.107 → 1.2.1-alpha.89

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 CHANGED
@@ -3,118 +3,6 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
- ## [1.2.1-alpha.107](https://gitlab.squiz.net/developer-experience/cmp/compare/v1.2.1-alpha.90...v1.2.1-alpha.107) (2022-09-21)
7
-
8
- **Note:** Version bump only for package @squiz/db-lib
9
-
10
-
11
-
12
-
13
-
14
- ## [1.2.1-alpha.106](https://gitlab.squiz.net/developer-experience/cmp/compare/v1.2.1-alpha.90...v1.2.1-alpha.106) (2022-09-02)
15
-
16
- **Note:** Version bump only for package @squiz/db-lib
17
-
18
-
19
-
20
-
21
-
22
- ## [1.2.1-alpha.105](https://gitlab.squiz.net/developer-experience/cmp/compare/v1.2.1-alpha.90...v1.2.1-alpha.105) (2022-08-26)
23
-
24
- **Note:** Version bump only for package @squiz/db-lib
25
-
26
-
27
-
28
-
29
-
30
- ## [1.2.1-alpha.104](https://gitlab.squiz.net/developer-experience/cmp/compare/v1.2.1-alpha.90...v1.2.1-alpha.104) (2022-08-23)
31
-
32
- **Note:** Version bump only for package @squiz/db-lib
33
-
34
-
35
-
36
-
37
-
38
- ## [1.2.1-alpha.103](https://gitlab.squiz.net/developer-experience/cmp/compare/v1.2.1-alpha.90...v1.2.1-alpha.103) (2022-08-23)
39
-
40
- **Note:** Version bump only for package @squiz/db-lib
41
-
42
-
43
-
44
-
45
-
46
- ## [1.2.1-alpha.102](https://gitlab.squiz.net/developer-experience/cmp/compare/v1.2.1-alpha.90...v1.2.1-alpha.102) (2022-08-23)
47
-
48
- **Note:** Version bump only for package @squiz/db-lib
49
-
50
-
51
-
52
-
53
-
54
- ## [1.2.1-alpha.101](https://gitlab.squiz.net/developer-experience/cmp/compare/v1.2.1-alpha.90...v1.2.1-alpha.101) (2022-08-19)
55
-
56
- **Note:** Version bump only for package @squiz/db-lib
57
-
58
-
59
-
60
-
61
-
62
- ## [1.2.1-alpha.100](https://gitlab.squiz.net/developer-experience/cmp/compare/v1.2.1-alpha.90...v1.2.1-alpha.100) (2022-08-18)
63
-
64
- **Note:** Version bump only for package @squiz/db-lib
65
-
66
-
67
-
68
-
69
-
70
- ## [1.2.1-alpha.99](https://gitlab.squiz.net/developer-experience/cmp/compare/v1.2.1-alpha.90...v1.2.1-alpha.99) (2022-08-18)
71
-
72
- **Note:** Version bump only for package @squiz/db-lib
73
-
74
-
75
-
76
-
77
-
78
- ## [1.2.1-alpha.98](https://gitlab.squiz.net/developer-experience/cmp/compare/v1.2.1-alpha.90...v1.2.1-alpha.98) (2022-08-17)
79
-
80
- **Note:** Version bump only for package @squiz/db-lib
81
-
82
-
83
-
84
-
85
-
86
- ## [1.2.1-alpha.97](https://gitlab.squiz.net/developer-experience/cmp/compare/v1.2.1-alpha.90...v1.2.1-alpha.97) (2022-08-17)
87
-
88
- **Note:** Version bump only for package @squiz/db-lib
89
-
90
-
91
-
92
-
93
-
94
- ## [1.2.1-alpha.96](https://gitlab.squiz.net/developer-experience/cmp/compare/v1.2.1-alpha.90...v1.2.1-alpha.96) (2022-08-12)
95
-
96
- **Note:** Version bump only for package @squiz/db-lib
97
-
98
-
99
-
100
-
101
-
102
- ## [1.2.1-alpha.95](https://gitlab.squiz.net/developer-experience/cmp/compare/v1.2.1-alpha.90...v1.2.1-alpha.95) (2022-08-10)
103
-
104
- **Note:** Version bump only for package @squiz/db-lib
105
-
106
-
107
-
108
-
109
-
110
- ## [1.2.1-alpha.90](https://gitlab.squiz.net/developer-experience/cmp/compare/v1.2.1-alpha.89...v1.2.1-alpha.90) (2022-08-05)
111
-
112
- **Note:** Version bump only for package @squiz/db-lib
113
-
114
-
115
-
116
-
117
-
118
6
  ## [1.2.1-alpha.89](https://gitlab.squiz.net/developer-experience/cmp/compare/v1.2.1-alpha.88...v1.2.1-alpha.89) (2022-08-05)
119
7
 
120
8
  **Note:** Version bump only for package @squiz/db-lib
package/package.json CHANGED
@@ -1,36 +1,37 @@
1
1
  {
2
2
  "name": "@squiz/db-lib",
3
- "version": "1.2.1-alpha.107",
3
+ "version": "1.2.1-alpha.89",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
7
+ "start": "node ./lib/index.js",
7
8
  "compile": "node build.js && npx tsc",
8
9
  "lint": "eslint ./src --ext .ts",
9
- "test": "jest -c jest.config.ts --passWithNoTests",
10
+ "test": "echo \"tested in integration\"",
11
+ "test:integration___": "jest -c jest.config.ts",
10
12
  "test:update-snapshots": "jest -c jest.config.ts --updateSnapshot",
11
13
  "clean": "rimraf \".tsbuildinfo\" \"./lib\""
12
14
  },
13
15
  "author": "",
14
16
  "license": "ISC",
15
17
  "devDependencies": {
16
- "@types/jest": "28.1.8",
18
+ "@types/jest": "28.1.6",
17
19
  "@types/node": "17.0.27",
18
20
  "@types/pg": "8.6.5",
19
- "esbuild": "0.15.6",
20
- "eslint": "8.22.0",
21
+ "esbuild": "0.14.49",
22
+ "eslint": "8.18.0",
21
23
  "fs-extra": "10.1.0",
22
24
  "jest": "28.1.3",
23
25
  "rimraf": "3.0.2",
24
- "ts-jest": "28.0.8",
26
+ "ts-jest": "28.0.5",
25
27
  "ts-loader": "9.3.1",
26
- "ts-node": "10.9.1",
28
+ "ts-node": "10.8.1",
27
29
  "typescript": "4.7.4"
28
30
  },
29
31
  "dependencies": {
30
- "@aws-sdk/client-secrets-manager": "3.121.0",
31
- "@squiz/dx-logger-lib": "^1.2.1-alpha.107",
32
+ "@aws-sdk/client-secrets-manager": "^3.121.0",
32
33
  "dotenv": "16.0.1",
33
- "pg": "8.7.3"
34
+ "pg": "^8.7.3"
34
35
  },
35
- "gitHead": "dc09e24c89b0f6d6afd23e958523cf9c9add89ec"
36
+ "gitHead": "d42ff3393c6e336ee05519872dbb58112ef045d1"
36
37
  }
@@ -14,46 +14,34 @@ export interface Writer<T> {
14
14
 
15
15
  export type Repository<T> = Reader<T> & Writer<T>;
16
16
 
17
- export type PageResult<T> = {
18
- items: T[];
19
- totalCount: number;
20
- pageSize: number;
21
- };
22
-
23
- export type SortDirection = 'desc' | 'asc';
24
- export const DEFAULT_PAGE_SIZE = 20;
25
-
26
- export abstract class AbstractRepository<T, ObjT extends T> implements Reader<T>, Writer<T> {
17
+ export abstract class AbstractRepository<T> implements Reader<T>, Writer<T> {
27
18
  protected tableName: string;
28
19
 
29
- /** object where the key is the model property name amd the value is sql column name */
30
20
  protected modelPropertyToSqlColumn: { [key in keyof T]: string };
31
- /** object where the key is the sql column name and the value is the model property name */
32
- protected sqlColumnToModelProperty: { [key: string]: string };
21
+ protected sqlColumnToModelProperty: { [key: string]: keyof T };
33
22
 
34
23
  constructor(
35
24
  protected repositories: Repositories,
36
25
  protected pool: Pool,
37
26
  tableName: string,
38
27
  mapping: { [key in keyof T]: string },
39
- protected classRef: { new (data?: Record<string, unknown>): ObjT },
28
+ protected classRef: { new (): T },
40
29
  ) {
41
30
  this.tableName = `"${tableName}"`;
42
31
 
43
32
  this.modelPropertyToSqlColumn = mapping;
44
-
45
33
  this.sqlColumnToModelProperty = Object.entries(mapping).reduce((prev, curr) => {
46
- const [modelProp, columnName] = curr as [string, string];
34
+ const [modelProp, columnName] = curr as [keyof T, string];
47
35
  prev[columnName] = modelProp;
48
36
  return prev;
49
- }, {} as { [key: string]: string });
37
+ }, {} as { [key: string]: keyof T });
50
38
  }
51
39
 
52
40
  protected async getConnection(): Promise<PoolClient> {
53
41
  return await this.pool.connect();
54
42
  }
55
43
 
56
- async create(value: ObjT, transactionClient: PoolClient | null = null): Promise<T> {
44
+ async create(value: Partial<T>, transactionClient: PoolClient | null = null): Promise<T> {
57
45
  const columns = Object.keys(value)
58
46
  .map((a) => `"${this.modelPropertyToSqlColumn[a as keyof T]}"`)
59
47
  .join(', ');
@@ -125,16 +113,16 @@ export abstract class AbstractRepository<T, ObjT extends T> implements Reader<T>
125
113
  return sql;
126
114
  }
127
115
 
128
- protected async executeQueryRaw(
116
+ protected async executeQuery(
129
117
  query: string,
130
118
  values: any[],
131
119
  transactionClient: PoolClient | null = null,
132
- ): Promise<any[]> {
120
+ ): Promise<T[]> {
133
121
  const client = transactionClient ?? (await this.getConnection());
134
122
  try {
135
123
  const result = await client.query(query, values);
136
124
 
137
- return result.rows;
125
+ return result.rows.map((a) => this.createAndHydrateModel(a));
138
126
  } finally {
139
127
  if (client && !transactionClient) {
140
128
  client.release();
@@ -142,24 +130,14 @@ export abstract class AbstractRepository<T, ObjT extends T> implements Reader<T>
142
130
  }
143
131
  }
144
132
 
145
- protected async executeQuery(
146
- query: string,
147
- values: any[],
148
- transactionClient: PoolClient | null = null,
149
- ): Promise<T[]> {
150
- const rows = await this.executeQueryRaw(query, values, transactionClient);
151
- return rows.map((a) => this.createAndHydrateModel(a));
152
- }
153
-
154
133
  protected createAndHydrateModel(row: any): T {
155
- const inputData: Record<string, unknown> = {};
134
+ const model = new this.classRef();
156
135
 
157
136
  for (const key of Object.keys(row)) {
158
- const translatedKey = this.sqlColumnToModelProperty[key];
159
- inputData[translatedKey] = row[key];
137
+ model[this.sqlColumnToModelProperty[key]] = row[key];
160
138
  }
161
139
 
162
- return new this.classRef(inputData);
140
+ return model;
163
141
  }
164
142
 
165
143
  async findOne(item: Partial<T>): Promise<T | undefined> {
@@ -194,61 +172,4 @@ export abstract class AbstractRepository<T, ObjT extends T> implements Reader<T>
194
172
 
195
173
  return result;
196
174
  }
197
-
198
- async getCount(item: Partial<T> | null = null): Promise<number> {
199
- let whereClause = '';
200
- if (item) {
201
- whereClause = `WHERE ${this.createWhereStringFromPartialModel(item)}`;
202
- }
203
- const result = await this.executeQueryRaw(
204
- `SELECT count(*)
205
- FROM ${this.tableName} ${whereClause}`,
206
- item ? Object.values(item) : [],
207
- );
208
- return parseInt(result[0].count);
209
- }
210
-
211
- async getPage(
212
- pageNumber: number,
213
- sortBy: (keyof T)[] = [],
214
- direction: SortDirection = 'asc',
215
- pageSize: number | null = null,
216
- item: Partial<T> | null = null,
217
- ): Promise<PageResult<T>> {
218
- if (pageSize === null) {
219
- pageSize = DEFAULT_PAGE_SIZE;
220
- }
221
- if (pageNumber <= 0) {
222
- throw new Error(`Page number value cannot be less than 1`);
223
- }
224
- if (pageSize <= 0) {
225
- throw new Error(`Page size value cannot be less than 1`);
226
- }
227
- let whereClause = '';
228
- if (item) {
229
- whereClause = `WHERE ${this.createWhereStringFromPartialModel(item)}`;
230
- }
231
-
232
- let orderByClause = '';
233
- if (sortBy.length) {
234
- orderByClause = `ORDER BY ${sortBy
235
- .map((a) => this.modelPropertyToSqlColumn[a as keyof T])
236
- .join(',')} ${direction}`;
237
- }
238
- const offset = (pageNumber - 1) * pageSize;
239
-
240
- const items = await this.executeQuery(
241
- `SELECT *
242
- FROM ${this.tableName} ${whereClause} ${orderByClause}
243
- OFFSET ${offset}
244
- LIMIT ${pageSize}`,
245
- item ? Object.values(item) : [],
246
- );
247
-
248
- return {
249
- items,
250
- totalCount: await this.getCount(item),
251
- pageSize,
252
- };
253
- }
254
175
  }
package/src/Migrator.ts CHANGED
@@ -1,15 +1,11 @@
1
1
  import fs from 'fs/promises';
2
2
  import { PoolClient } from 'pg';
3
3
  import path from 'path';
4
- import os from 'os';
5
- import { getLogger } from '@squiz/dx-logger-lib';
6
4
 
7
5
  // Be carful about changing this value. This needs to be consistent across deployments
8
6
  // this ID is used to signal other running instances that a migration is executing.
9
7
  const MIGRATION_ADVISORY_LOCK = 4569465;
10
8
 
11
- const logger = getLogger({ name: 'db-migrator', meta: { pid: process.pid, hostname: os.hostname() } });
12
-
13
9
  export class Migrator {
14
10
  constructor(protected migrationDir: string, protected migrationList: string[], protected pool: PoolClient) {}
15
11
 
@@ -29,15 +25,15 @@ export class Migrator {
29
25
  protected async applyMigration(migration: string, sql: string) {
30
26
  try {
31
27
  const result = await this.pool.query(sql);
32
- logger.info('Applying ' + migration);
28
+ console.log(process.pid, 'Applying ' + migration);
33
29
 
34
30
  if (result.rowCount !== undefined) {
35
- logger.info('affected rows', result.rowCount);
31
+ console.log(process.pid, 'affected rows', result.rowCount);
36
32
  }
37
33
 
38
34
  await this.pool.query('insert into __migrations__ (id) values ($1)', [migration]);
39
35
  } catch (e) {
40
- logger.info('error occurred running migration', migration, e);
36
+ console.log(process.pid, 'error occurred running migration', migration, e);
41
37
  throw e;
42
38
  }
43
39
  }
@@ -83,18 +79,18 @@ export class Migrator {
83
79
  const lockObtained = await this.tryToObtainLock();
84
80
 
85
81
  if (lockObtained === false) {
86
- logger.info('migration already running');
82
+ console.log(process.pid, 'migration already running');
87
83
  await sleep(500);
88
84
  return await this.migrate();
89
85
  }
90
86
 
91
87
  await this.runMigrations();
92
- logger.info('completed migration');
88
+ console.log(process.pid, 'completed migration');
93
89
  await this.releaseLock();
94
90
 
95
91
  this.dispose();
96
92
  } catch (e) {
97
- logger.info('migration failed releasing lock');
93
+ console.log(process.pid, 'migration failed releasing lock');
98
94
  await this.releaseLock();
99
95
  throw e;
100
96
  }
@@ -105,11 +101,11 @@ export class Migrator {
105
101
  const pending = await this.getPending(this.migrationList, appliedMigrations);
106
102
 
107
103
  if (pending.length === 0) {
108
- logger.info('No pending migrations');
104
+ console.log(process.pid, 'No pending migrations');
109
105
  return;
110
106
  }
111
107
 
112
- logger.info('Pending migrations:\n\t', pending.join('\n\t'));
108
+ console.log(process.pid, 'Pending migrations:\n\t', pending.join('\n\t'));
113
109
 
114
110
  for (const migration of pending) {
115
111
  await this.runMigration(migration);
@@ -125,7 +121,7 @@ export class Migrator {
125
121
 
126
122
  await this.pool.query('COMMIT');
127
123
  } catch (e) {
128
- logger.error('migration failed', migration, e);
124
+ console.log(process.pid, 'migration failed', migration, e);
129
125
  await this.pool.query('ROLLBACK');
130
126
  throw e;
131
127
  }
package/src/index.ts CHANGED
@@ -3,8 +3,3 @@ export * from './ConnectionManager';
3
3
  export * from './Migrator';
4
4
  export * from './Repositories';
5
5
  export * from './getConnectionInfo';
6
-
7
- // Postgres
8
- export * from './PostgresErrorCodes';
9
-
10
- export { Pool } from 'pg';
package/tsconfig.json CHANGED
@@ -7,11 +7,7 @@
7
7
  "emitDeclarationOnly": true,
8
8
  "rootDir": "./src"
9
9
  },
10
- "references": [
11
- {
12
- "path": "../dx-logger-lib"
13
- }
14
- ],
10
+ "references": [],
15
11
  "include": ["src/**/*.ts", "src/**/*.json"],
16
12
  "exclude": ["jest.config.ts"]
17
13
  }
@@ -1,53 +0,0 @@
1
- import { PoolClient, Pool } from 'pg';
2
- import { Repositories } from './Repositories';
3
- export interface Reader<T> {
4
- find(item: Partial<T>): Promise<T[]>;
5
- findOne(id: string | Partial<T>): Promise<T | undefined>;
6
- }
7
- export interface Writer<T> {
8
- create(value: Partial<T>): Promise<T>;
9
- update(where: Partial<T>, newValue: Partial<T>): Promise<T[]>;
10
- delete(where: Partial<T>): Promise<number>;
11
- }
12
- export declare type Repository<T> = Reader<T> & Writer<T>;
13
- export declare type PageResult<T> = {
14
- items: T[];
15
- totalCount: number;
16
- pageSize: number;
17
- };
18
- export declare type SortDirection = 'desc' | 'asc';
19
- export declare const DEFAULT_PAGE_SIZE = 20;
20
- export declare abstract class AbstractRepository<T, ObjT extends T> implements Reader<T>, Writer<T> {
21
- protected repositories: Repositories;
22
- protected pool: Pool;
23
- protected classRef: {
24
- new (data?: Record<string, unknown>): ObjT;
25
- };
26
- protected tableName: string;
27
- /** object where the key is the model property name amd the value is sql column name */
28
- protected modelPropertyToSqlColumn: {
29
- [key in keyof T]: string;
30
- };
31
- /** object where the key is the sql column name and the value is the model property name */
32
- protected sqlColumnToModelProperty: {
33
- [key: string]: string;
34
- };
35
- constructor(repositories: Repositories, pool: Pool, tableName: string, mapping: {
36
- [key in keyof T]: string;
37
- }, classRef: {
38
- new (data?: Record<string, unknown>): ObjT;
39
- });
40
- protected getConnection(): Promise<PoolClient>;
41
- create(value: ObjT, transactionClient?: PoolClient | null): Promise<T>;
42
- update(where: Partial<T>, newValue: Partial<T>, transactionClient?: PoolClient | null): Promise<T[]>;
43
- delete(where: Partial<T>, transactionClient?: PoolClient | null): Promise<number>;
44
- protected createWhereStringFromPartialModel(values: Partial<T>, initialIndex?: number): string;
45
- protected executeQueryRaw(query: string, values: any[], transactionClient?: PoolClient | null): Promise<any[]>;
46
- protected executeQuery(query: string, values: any[], transactionClient?: PoolClient | null): Promise<T[]>;
47
- protected createAndHydrateModel(row: any): T;
48
- findOne(item: Partial<T>): Promise<T | undefined>;
49
- find(item: Partial<T>): Promise<T[]>;
50
- findAll(): Promise<T[]>;
51
- getCount(item?: Partial<T> | null): Promise<number>;
52
- getPage(pageNumber: number, sortBy?: (keyof T)[], direction?: SortDirection, pageSize?: number | null, item?: Partial<T> | null): Promise<PageResult<T>>;
53
- }
@@ -1,25 +0,0 @@
1
- import { Pool } from 'pg';
2
- import { PoolClient } from 'pg';
3
- import { Repositories } from './Repositories';
4
- export interface DbConnection {
5
- user: string;
6
- password: string;
7
- host: string;
8
- port: number;
9
- database: string;
10
- }
11
- export interface ConnectionStringObj {
12
- connectionString: string;
13
- }
14
- export declare type TransactionClient = PoolClient;
15
- export declare class ConnectionManager<T extends Repositories> {
16
- protected applicationName: string;
17
- protected migrationDirectory: string;
18
- protected migrationList: string[];
19
- readonly pool: Pool;
20
- readonly repositories: T;
21
- constructor(applicationName: string, connection: string | DbConnection, migrationDirectory: string, migrationList: string[], repositoryCreator: (dbManager: ConnectionManager<T>) => T);
22
- applyMigrations(): Promise<void>;
23
- close(): Promise<void>;
24
- executeInTransaction<T>(func: (client: TransactionClient) => Promise<T>): Promise<T>;
25
- }
package/lib/Migrator.d.ts DELETED
@@ -1,18 +0,0 @@
1
- import { PoolClient } from 'pg';
2
- export declare class Migrator {
3
- protected migrationDir: string;
4
- protected migrationList: string[];
5
- protected pool: PoolClient;
6
- constructor(migrationDir: string, migrationList: string[], pool: PoolClient);
7
- protected ensureMigrationTableExists(): Promise<import("pg").QueryResult<any>>;
8
- protected getAppliedMigrations(): Promise<any[]>;
9
- protected applyMigration(migration: string, sql: string): Promise<void>;
10
- protected getPending(migrationsList: string[], appliedMigrations: string[]): Promise<string[]>;
11
- protected getSql(migration: string): Promise<string>;
12
- protected tryToObtainLock(): Promise<boolean>;
13
- protected releaseLock(): Promise<void>;
14
- migrate(): Promise<any>;
15
- protected runMigrations(): Promise<void>;
16
- protected runMigration(migration: string): Promise<void>;
17
- protected dispose(): void;
18
- }