sedentary-pg 0.0.11 → 0.0.12

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2017-2020 Daniele Ricci
3
+ Copyright (c) 2017 Daniele Ricci
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,15 +1,15 @@
1
1
  # sedentary-pg
2
2
 
3
- [![NPM version][npm-badge]][npm-url]
4
- [![Types][types-badge]][npm-url]
5
- [![NPM downloads][npm-downloads-badge]][npm-url]
6
-
7
3
  [![Build Status][travis-badge]][travis-url]
8
4
  [![Code Climate][code-badge]][code-url]
9
5
  [![Test Coverage][cover-badge]][code-url]
10
6
 
11
- [![Dependents][deps-badge]][npm-url]
7
+ [![NPM version][npm-badge]][npm-url]
8
+ [![NPM downloads][npm-downloads-badge]][npm-url]
12
9
  [![Stars][stars-badge]][github-url]
10
+
11
+ [![Types][types-badge]][npm-url]
12
+ [![Dependents][deps-badge]][npm-url]
13
13
  [![Donate][donate-badge]][donate-url]
14
14
 
15
15
  [code-badge]: https://codeclimate.com/github/iccicci/sedentary-pg/badges/gpa.svg
@@ -24,7 +24,7 @@
24
24
  [npm-url]: https://www.npmjs.com/package/sedentary-pg
25
25
  [stars-badge]: https://badgen.net/github/stars/iccicci/sedentary-pg?icon=github&cache=300
26
26
  [travis-badge]: https://badgen.net/travis/iccicci/sedentary-pg?icon=travis&cache=300
27
- [travis-url]: https://travis-ci.com/iccicci/sedentary-pg
27
+ [travis-url]: https://app.travis-ci.com/github/iccicci/sedentary-pg
28
28
  [types-badge]: https://badgen.net/npm/types/sedentary-pg?color=green&icon=typescript&cache=300
29
29
 
30
30
  # under development
package/lib/pgdb.d.ts CHANGED
@@ -2,6 +2,7 @@ import { PoolConfig } from "pg";
2
2
  import { DB, Field, Table } from "sedentary/lib/db";
3
3
  export declare class PGDB extends DB {
4
4
  private client;
5
+ private indexes;
5
6
  private pool;
6
7
  private version;
7
8
  constructor(connection: PoolConfig, log: (message: string) => void);
@@ -15,6 +16,7 @@ export declare class PGDB extends DB {
15
16
  sync(): Promise<void>;
16
17
  syncConstraints(table: Table): Promise<void>;
17
18
  syncFields(table: Table): Promise<void>;
19
+ syncIndexes(table: Table): Promise<void>;
18
20
  syncSequence(table: Table): Promise<void>;
19
21
  syncTable(table: Table): Promise<void>;
20
22
  }
package/lib/pgdb.js CHANGED
@@ -71,7 +71,31 @@ class PGDB extends db_1.DB {
71
71
  if (table.fields.filter(f => f.fieldName === res.rows[i].attname).length === 0)
72
72
  await this.dropField(table.tableName, res.rows[i].attname);
73
73
  }
74
- async dropIndexes(table) { }
74
+ async dropIndexes(table) {
75
+ const { indexes, oid } = table;
76
+ const iobject = {};
77
+ const res = await this.client.query("SELECT amname, attname, indisunique, relname FROM pg_class, pg_index, pg_attribute, pg_am WHERE indrelid = $1 AND indexrelid = pg_class.oid AND attrelid = pg_class.oid AND relam = pg_am.oid ORDER BY attnum", [oid]);
78
+ for (const row of res.rows) {
79
+ const { amname, attname, indisunique, relname } = row;
80
+ if (iobject[relname])
81
+ iobject[relname].fields.push(attname);
82
+ else
83
+ iobject[relname] = { fields: [attname], name: relname, type: amname, unique: indisunique };
84
+ }
85
+ this.indexes = [];
86
+ for (const index of indexes) {
87
+ const { name } = index;
88
+ if (iobject[name] && this.indexesEq(index, iobject[name])) {
89
+ this.indexes.push(name);
90
+ delete iobject[name];
91
+ }
92
+ }
93
+ for (const index of Object.keys(iobject).sort()) {
94
+ const statement = `DROP INDEX ${index}`;
95
+ this.log(statement);
96
+ await this.client.query(statement);
97
+ }
98
+ }
75
99
  async end() {
76
100
  await this.pool.end();
77
101
  }
@@ -119,10 +143,9 @@ class PGDB extends db_1.DB {
119
143
  }
120
144
  async syncFields(table) {
121
145
  const { fields, oid, tableName } = table;
122
- for (const i in fields) {
123
- const field = fields[i];
124
- const { fieldName, size } = field;
125
- const defaultValue = field.defaultValue === undefined ? undefined : pg_format_1.default("%L", field.defaultValue);
146
+ for (const field of fields) {
147
+ const { fieldName, notNull, size } = field;
148
+ const defaultValue = field.defaultValue === undefined ? undefined : (0, pg_format_1.default)("%L", field.defaultValue);
126
149
  const [base, type] = this.fieldType(field);
127
150
  const res = await this.client.query(`SELECT *${this.version >= 12 ? ", pg_get_expr(pg_attrdef.adbin, pg_attrdef.adrelid) AS adsrc" : ""} FROM pg_type, pg_attribute LEFT JOIN pg_attrdef ON adrelid = attrelid AND adnum = attnum WHERE attrelid = $1 AND attnum > 0 AND atttypid = pg_type.oid AND attislocal = 't' AND attname = $2`, [oid, fieldName]);
128
151
  const addField = async () => {
@@ -142,17 +165,26 @@ class PGDB extends db_1.DB {
142
165
  this.log(statement);
143
166
  await this.client.query(statement);
144
167
  };
168
+ const setNotNull = async (isNull) => {
169
+ if (isNull === notNull)
170
+ return;
171
+ const statement = `ALTER TABLE ${tableName} ALTER COLUMN ${fieldName} ${notNull ? "SET" : "DROP"} NOT NULL`;
172
+ this.log(statement);
173
+ await this.client.query(statement);
174
+ };
145
175
  if (!res.rowCount) {
146
176
  await addField();
147
177
  await setDefault();
178
+ await setNotNull(false);
148
179
  }
149
180
  else {
150
- const { adsrc, typname, atttypmod } = res.rows[0];
181
+ const { adsrc, attnotnull, atttypmod, typname } = res.rows[0];
151
182
  if (types[typname] !== base || (base === "VARCHAR" && (size ? size + 4 !== atttypmod : atttypmod !== -1))) {
152
183
  if (needDrop.filter(([type, name]) => field.type === type && typname === name).length) {
153
184
  await this.dropField(tableName, fieldName);
154
185
  await addField();
155
186
  await setDefault();
187
+ await setNotNull(false);
156
188
  }
157
189
  else {
158
190
  if (adsrc)
@@ -162,14 +194,29 @@ class PGDB extends db_1.DB {
162
194
  this.log(statement);
163
195
  await this.client.query(statement);
164
196
  await setDefault();
197
+ await setNotNull(attnotnull);
165
198
  }
166
199
  }
167
200
  else if (defaultValue === undefined) {
168
201
  if (adsrc)
169
202
  dropDefault();
203
+ await setNotNull(attnotnull);
170
204
  }
171
- else if (!adsrc || adsrc.split("::")[0] !== defaultValue)
205
+ else if (!adsrc || adsrc.split("::")[0] !== defaultValue) {
172
206
  await setDefault();
207
+ await setNotNull(attnotnull);
208
+ }
209
+ }
210
+ }
211
+ }
212
+ async syncIndexes(table) {
213
+ const { indexes, tableName } = table;
214
+ for (const index of indexes) {
215
+ const { fields, name, type, unique } = index;
216
+ if (this.indexes.indexOf(name) === -1) {
217
+ const statement = `CREATE${unique ? " UNIQUE" : ""} INDEX ${name} ON ${tableName} USING ${type} (${fields.join(", ")})`;
218
+ this.log(statement);
219
+ await this.client.query(statement);
173
220
  }
174
221
  }
175
222
  }
package/lib/pgdb.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Pool, PoolClient, PoolConfig } from "pg";
2
2
  import format from "pg-format";
3
- import { DB, Field, Table } from "sedentary/lib/db";
3
+ import { DB, Field, IndexDef, Table } from "sedentary/lib/db";
4
4
 
5
5
  const needDrop = [
6
6
  ["DATETIME", "int2"],
@@ -18,6 +18,7 @@ const types = { int2: "SMALLINT", int4: "INTEGER", int8: "BIGINT", varchar: "VAR
18
18
 
19
19
  export class PGDB extends DB {
20
20
  private client: PoolClient;
21
+ private indexes: string[];
21
22
  private pool: Pool;
22
23
  private version: number;
23
24
 
@@ -83,7 +84,38 @@ export class PGDB extends DB {
83
84
  for(const i in res.rows) if(table.fields.filter(f => f.fieldName === res.rows[i].attname).length === 0) await this.dropField(table.tableName, res.rows[i].attname);
84
85
  }
85
86
 
86
- async dropIndexes(table: Table): Promise<void> {}
87
+ async dropIndexes(table: Table): Promise<void> {
88
+ const { indexes, oid } = table;
89
+ const iobject: { [key: string]: IndexDef } = {};
90
+ const res = await this.client.query(
91
+ "SELECT amname, attname, indisunique, relname FROM pg_class, pg_index, pg_attribute, pg_am WHERE indrelid = $1 AND indexrelid = pg_class.oid AND attrelid = pg_class.oid AND relam = pg_am.oid ORDER BY attnum",
92
+ [oid]
93
+ );
94
+
95
+ for(const row of res.rows) {
96
+ const { amname, attname, indisunique, relname } = row;
97
+
98
+ if(iobject[relname]) iobject[relname].fields.push(attname);
99
+ else iobject[relname] = { fields: [attname], name: relname, type: amname, unique: indisunique };
100
+ }
101
+
102
+ this.indexes = [];
103
+ for(const index of indexes) {
104
+ const { name } = index;
105
+
106
+ if(iobject[name] && this.indexesEq(index, iobject[name])) {
107
+ this.indexes.push(name);
108
+ delete iobject[name];
109
+ }
110
+ }
111
+
112
+ for(const index of Object.keys(iobject).sort()) {
113
+ const statement = `DROP INDEX ${index}`;
114
+
115
+ this.log(statement);
116
+ await this.client.query(statement);
117
+ }
118
+ }
87
119
 
88
120
  async end(): Promise<void> {
89
121
  await this.pool.end();
@@ -144,9 +176,8 @@ export class PGDB extends DB {
144
176
  async syncFields(table: Table): Promise<void> {
145
177
  const { fields, oid, tableName } = table;
146
178
 
147
- for(const i in fields) {
148
- const field = fields[i];
149
- const { fieldName, size } = field;
179
+ for(const field of fields) {
180
+ const { fieldName, notNull, size } = field;
150
181
  const defaultValue = field.defaultValue === undefined ? undefined : format("%L", field.defaultValue);
151
182
  const [base, type] = this.fieldType(field);
152
183
 
@@ -180,17 +211,28 @@ export class PGDB extends DB {
180
211
  await this.client.query(statement);
181
212
  };
182
213
 
214
+ const setNotNull = async (isNull: boolean) => {
215
+ if(isNull === notNull) return;
216
+
217
+ const statement = `ALTER TABLE ${tableName} ALTER COLUMN ${fieldName} ${notNull ? "SET" : "DROP"} NOT NULL`;
218
+
219
+ this.log(statement);
220
+ await this.client.query(statement);
221
+ };
222
+
183
223
  if(! res.rowCount) {
184
224
  await addField();
185
225
  await setDefault();
226
+ await setNotNull(false);
186
227
  } else {
187
- const { adsrc, typname, atttypmod } = res.rows[0];
228
+ const { adsrc, attnotnull, atttypmod, typname } = res.rows[0];
188
229
 
189
230
  if(types[typname] !== base || (base === "VARCHAR" && (size ? size + 4 !== atttypmod : atttypmod !== -1))) {
190
231
  if(needDrop.filter(([type, name]) => field.type === type && typname === name).length) {
191
232
  await this.dropField(tableName, fieldName);
192
233
  await addField();
193
234
  await setDefault();
235
+ await setNotNull(false);
194
236
  } else {
195
237
  if(adsrc) dropDefault();
196
238
 
@@ -200,10 +242,30 @@ export class PGDB extends DB {
200
242
  this.log(statement);
201
243
  await this.client.query(statement);
202
244
  await setDefault();
245
+ await setNotNull(attnotnull);
203
246
  }
204
247
  } else if(defaultValue === undefined) {
205
248
  if(adsrc) dropDefault();
206
- } else if(! adsrc || adsrc.split("::")[0] !== defaultValue) await setDefault();
249
+ await setNotNull(attnotnull);
250
+ } else if(! adsrc || adsrc.split("::")[0] !== defaultValue) {
251
+ await setDefault();
252
+ await setNotNull(attnotnull);
253
+ }
254
+ }
255
+ }
256
+ }
257
+
258
+ async syncIndexes(table: Table): Promise<void> {
259
+ const { indexes, tableName } = table;
260
+
261
+ for(const index of indexes) {
262
+ const { fields, name, type, unique } = index;
263
+
264
+ if(this.indexes.indexOf(name) === -1) {
265
+ const statement = `CREATE${unique ? " UNIQUE" : ""} INDEX ${name} ON ${tableName} USING ${type} (${fields.join(", ")})`;
266
+
267
+ this.log(statement);
268
+ await this.client.query(statement);
207
269
  }
208
270
  }
209
271
  }
package/package.json CHANGED
@@ -2,29 +2,29 @@
2
2
  "author": "Daniele Ricci <daniele.icc@gmail.com> (https://github.com/iccicci)",
3
3
  "bugs": "https://github.com/iccicci/sedentary-pg/issues",
4
4
  "dependencies": {
5
- "@types/pg": "7.14.7",
6
- "@types/pg-format": "1.0.1",
7
- "pg": "8.5.1",
5
+ "@types/pg": "8.6.1",
6
+ "@types/pg-format": "1.0.2",
7
+ "pg": "8.7.1",
8
8
  "pg-format": "1.0.4",
9
- "sedentary": "0.0.11"
9
+ "sedentary": "0.0.12"
10
10
  },
11
11
  "description": "The ORM which never needs to migrate - PostgreSQL",
12
12
  "devDependencies": {
13
- "@types/mocha": "8.2.0",
14
- "@types/node": "14.14.16",
13
+ "@types/mocha": "9.0.0",
14
+ "@types/node": "16.11.6",
15
15
  "@types/yamljs": "0.2.31",
16
- "@typescript-eslint/eslint-plugin": "4.11.1",
17
- "@typescript-eslint/parser": "4.11.1",
18
- "eslint": "7.16.0",
19
- "mocha": "8.2.1",
16
+ "@typescript-eslint/eslint-plugin": "5.3.0",
17
+ "@typescript-eslint/parser": "5.3.0",
18
+ "eslint": "8.2.0",
19
+ "mocha": "9.1.3",
20
20
  "nyc": "15.1.0",
21
- "prettier": "2.2.1",
22
- "ts-node": "9.1.1",
23
- "typescript": "4.1.3",
21
+ "prettier": "2.4.1",
22
+ "ts-node": "10.4.0",
23
+ "typescript": "4.4.4",
24
24
  "yamljs": "0.3.0"
25
25
  },
26
26
  "engines": {
27
- "node": ">=10.0"
27
+ "node": ">=12.0"
28
28
  },
29
29
  "homepage": "https://github.com/iccicci/sedentary-pg#readme",
30
30
  "keywords": [
@@ -59,5 +59,5 @@
59
59
  "version": "node -r ts-node/register utils.ts version"
60
60
  },
61
61
  "types": "index.d.ts",
62
- "version": "0.0.11"
63
- }
62
+ "version": "0.0.12"
63
+ }