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 +1 -1
- package/README.md +6 -6
- package/lib/pgdb.d.ts +2 -0
- package/lib/pgdb.js +54 -7
- package/lib/pgdb.ts +69 -7
- package/package.json +16 -16
package/LICENSE
CHANGED
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
|
-
[![
|
|
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
|
|
123
|
-
const
|
|
124
|
-
const
|
|
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,
|
|
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
|
|
148
|
-
const
|
|
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,
|
|
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
|
-
|
|
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": "
|
|
6
|
-
"@types/pg-format": "1.0.
|
|
7
|
-
"pg": "8.
|
|
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.
|
|
9
|
+
"sedentary": "0.0.12"
|
|
10
10
|
},
|
|
11
11
|
"description": "The ORM which never needs to migrate - PostgreSQL",
|
|
12
12
|
"devDependencies": {
|
|
13
|
-
"@types/mocha": "
|
|
14
|
-
"@types/node": "
|
|
13
|
+
"@types/mocha": "9.0.0",
|
|
14
|
+
"@types/node": "16.11.6",
|
|
15
15
|
"@types/yamljs": "0.2.31",
|
|
16
|
-
"@typescript-eslint/eslint-plugin": "
|
|
17
|
-
"@typescript-eslint/parser": "
|
|
18
|
-
"eslint": "
|
|
19
|
-
"mocha": "
|
|
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.
|
|
22
|
-
"ts-node": "
|
|
23
|
-
"typescript": "4.
|
|
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": ">=
|
|
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.
|
|
63
|
-
}
|
|
62
|
+
"version": "0.0.12"
|
|
63
|
+
}
|