sedentary-pg 0.0.8 → 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/index.js +2 -0
- package/lib/pgdb.d.ts +6 -2
- package/lib/pgdb.js +133 -18
- package/lib/pgdb.ts +160 -20
- package/package.json +19 -17
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/index.js
CHANGED
|
@@ -6,6 +6,8 @@ const pgdb_1 = require("./lib/pgdb");
|
|
|
6
6
|
class SedentaryPG extends sedentary_1.Sedentary {
|
|
7
7
|
constructor(connection, options) {
|
|
8
8
|
super("", options);
|
|
9
|
+
if (!(connection instanceof Object))
|
|
10
|
+
throw new Error("SedentaryPG.constructor: 'connection' argument: Wrong type, expected 'Object'");
|
|
9
11
|
this.db = new pgdb_1.PGDB(connection, this.log);
|
|
10
12
|
}
|
|
11
13
|
}
|
package/lib/pgdb.d.ts
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
import { PoolConfig } from "pg";
|
|
2
|
-
import { DB, Field, Table
|
|
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;
|
|
7
|
+
private version;
|
|
6
8
|
constructor(connection: PoolConfig, log: (message: string) => void);
|
|
7
9
|
connect(): Promise<void>;
|
|
8
10
|
dropConstraints(table: Table): Promise<void>;
|
|
11
|
+
dropField(tableName: string, fieldName: string): Promise<void>;
|
|
9
12
|
dropFields(table: Table): Promise<void>;
|
|
10
13
|
dropIndexes(table: Table): Promise<void>;
|
|
11
14
|
end(): Promise<void>;
|
|
12
|
-
fieldType(field: Field<
|
|
15
|
+
fieldType(field: Field<unknown, unknown>): string[];
|
|
13
16
|
sync(): Promise<void>;
|
|
14
17
|
syncConstraints(table: Table): Promise<void>;
|
|
15
18
|
syncFields(table: Table): Promise<void>;
|
|
19
|
+
syncIndexes(table: Table): Promise<void>;
|
|
16
20
|
syncSequence(table: Table): Promise<void>;
|
|
17
21
|
syncTable(table: Table): Promise<void>;
|
|
18
22
|
}
|
package/lib/pgdb.js
CHANGED
|
@@ -1,8 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.PGDB = void 0;
|
|
4
7
|
const pg_1 = require("pg");
|
|
8
|
+
const pg_format_1 = __importDefault(require("pg-format"));
|
|
5
9
|
const db_1 = require("sedentary/lib/db");
|
|
10
|
+
const needDrop = [
|
|
11
|
+
["DATETIME", "int2"],
|
|
12
|
+
["DATETIME", "int4"],
|
|
13
|
+
["DATETIME", "int8"],
|
|
14
|
+
["INT", "timestamptz"],
|
|
15
|
+
["INT8", "timestamptz"]
|
|
16
|
+
];
|
|
17
|
+
const needUsing = [
|
|
18
|
+
["DATETIME", "varchar"],
|
|
19
|
+
["INT", "varchar"],
|
|
20
|
+
["INT8", "varchar"]
|
|
21
|
+
];
|
|
22
|
+
const types = { int2: "SMALLINT", int4: "INTEGER", int8: "BIGINT", varchar: "VARCHAR" };
|
|
6
23
|
class PGDB extends db_1.DB {
|
|
7
24
|
constructor(connection, log) {
|
|
8
25
|
super(log);
|
|
@@ -10,6 +27,8 @@ class PGDB extends db_1.DB {
|
|
|
10
27
|
}
|
|
11
28
|
async connect() {
|
|
12
29
|
this.client = await this.pool.connect();
|
|
30
|
+
const res = await this.client.query("SELECT version()");
|
|
31
|
+
this.version = parseInt(res.rows[0].version.split(" ")[1].split(".")[0], 10);
|
|
13
32
|
}
|
|
14
33
|
async dropConstraints(table) {
|
|
15
34
|
let place = 1;
|
|
@@ -41,28 +60,58 @@ class PGDB extends db_1.DB {
|
|
|
41
60
|
await this.client.query(statement);
|
|
42
61
|
}
|
|
43
62
|
}
|
|
63
|
+
async dropField(tableName, fieldName) {
|
|
64
|
+
const statement = `ALTER TABLE ${tableName} DROP COLUMN ${fieldName}`;
|
|
65
|
+
this.log(statement);
|
|
66
|
+
await this.client.query(statement);
|
|
67
|
+
}
|
|
44
68
|
async dropFields(table) {
|
|
45
69
|
const res = await this.client.query("SELECT attname FROM pg_attribute WHERE attrelid = $1 AND attnum > 0 AND attisdropped = false AND attinhcount = 0", [table.oid]);
|
|
46
|
-
for (const i in res.rows)
|
|
47
|
-
if (table.fields.filter(f => f.fieldName === res.rows[i].attname).length === 0)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
70
|
+
for (const i in res.rows)
|
|
71
|
+
if (table.fields.filter(f => f.fieldName === res.rows[i].attname).length === 0)
|
|
72
|
+
await this.dropField(table.tableName, res.rows[i].attname);
|
|
73
|
+
}
|
|
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];
|
|
51
91
|
}
|
|
52
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
|
+
}
|
|
53
98
|
}
|
|
54
|
-
async dropIndexes(table) { }
|
|
55
99
|
async end() {
|
|
56
100
|
await this.pool.end();
|
|
57
101
|
}
|
|
58
102
|
fieldType(field) {
|
|
59
103
|
const { size, type } = field;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
104
|
+
let ret;
|
|
105
|
+
switch (type) {
|
|
106
|
+
case "DATETIME":
|
|
107
|
+
return ["DATETIME", "TIMESTAMP (3) WITH TIME ZONE"];
|
|
108
|
+
case "INT":
|
|
109
|
+
ret = size === 2 ? "SMALLINT" : "INTEGER";
|
|
110
|
+
return [ret, ret];
|
|
111
|
+
case "INT8":
|
|
112
|
+
return ["BIGINT", "BIGINT"];
|
|
113
|
+
case "VARCHAR":
|
|
114
|
+
return ["VARCHAR", "VARCHAR" + (size ? `(${size})` : "")];
|
|
66
115
|
}
|
|
67
116
|
throw new Error(`Unknown type: '${type}', '${size}'`);
|
|
68
117
|
}
|
|
@@ -93,16 +142,82 @@ class PGDB extends db_1.DB {
|
|
|
93
142
|
}
|
|
94
143
|
}
|
|
95
144
|
async syncFields(table) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const
|
|
145
|
+
const { fields, oid, tableName } = table;
|
|
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);
|
|
149
|
+
const [base, type] = this.fieldType(field);
|
|
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]);
|
|
151
|
+
const addField = async () => {
|
|
152
|
+
const statement = `ALTER TABLE ${tableName} ADD COLUMN ${fieldName} ${type}`;
|
|
153
|
+
this.log(statement);
|
|
154
|
+
await this.client.query(statement);
|
|
155
|
+
};
|
|
156
|
+
const dropDefault = async () => {
|
|
157
|
+
const statement = `ALTER TABLE ${tableName} ALTER COLUMN ${fieldName} DROP DEFAULT`;
|
|
158
|
+
this.log(statement);
|
|
159
|
+
await this.client.query(statement);
|
|
160
|
+
};
|
|
161
|
+
const setDefault = async () => {
|
|
162
|
+
if (defaultValue === undefined)
|
|
163
|
+
return;
|
|
164
|
+
const statement = `ALTER TABLE ${tableName} ALTER COLUMN ${fieldName} SET DEFAULT ${defaultValue}`;
|
|
165
|
+
this.log(statement);
|
|
166
|
+
await this.client.query(statement);
|
|
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
|
+
};
|
|
99
175
|
if (!res.rowCount) {
|
|
100
|
-
|
|
176
|
+
await addField();
|
|
177
|
+
await setDefault();
|
|
178
|
+
await setNotNull(false);
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
const { adsrc, attnotnull, atttypmod, typname } = res.rows[0];
|
|
182
|
+
if (types[typname] !== base || (base === "VARCHAR" && (size ? size + 4 !== atttypmod : atttypmod !== -1))) {
|
|
183
|
+
if (needDrop.filter(([type, name]) => field.type === type && typname === name).length) {
|
|
184
|
+
await this.dropField(tableName, fieldName);
|
|
185
|
+
await addField();
|
|
186
|
+
await setDefault();
|
|
187
|
+
await setNotNull(false);
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
if (adsrc)
|
|
191
|
+
dropDefault();
|
|
192
|
+
const using = needUsing.filter(([type, name]) => field.type === type && typname === name).length ? " USING " + fieldName + "::" + type : "";
|
|
193
|
+
const statement = `ALTER TABLE ${tableName} ALTER COLUMN ${fieldName} TYPE ${type}${using}`;
|
|
194
|
+
this.log(statement);
|
|
195
|
+
await this.client.query(statement);
|
|
196
|
+
await setDefault();
|
|
197
|
+
await setNotNull(attnotnull);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
else if (defaultValue === undefined) {
|
|
201
|
+
if (adsrc)
|
|
202
|
+
dropDefault();
|
|
203
|
+
await setNotNull(attnotnull);
|
|
204
|
+
}
|
|
205
|
+
else if (!adsrc || adsrc.split("::")[0] !== defaultValue) {
|
|
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(", ")})`;
|
|
101
218
|
this.log(statement);
|
|
102
219
|
await this.client.query(statement);
|
|
103
220
|
}
|
|
104
|
-
else
|
|
105
|
-
console.log(res.rows[0].typname);
|
|
106
221
|
}
|
|
107
222
|
}
|
|
108
223
|
async syncSequence(table) {
|
package/lib/pgdb.ts
CHANGED
|
@@ -1,9 +1,26 @@
|
|
|
1
1
|
import { Pool, PoolClient, PoolConfig } from "pg";
|
|
2
|
-
import
|
|
2
|
+
import format from "pg-format";
|
|
3
|
+
import { DB, Field, IndexDef, Table } from "sedentary/lib/db";
|
|
4
|
+
|
|
5
|
+
const needDrop = [
|
|
6
|
+
["DATETIME", "int2"],
|
|
7
|
+
["DATETIME", "int4"],
|
|
8
|
+
["DATETIME", "int8"],
|
|
9
|
+
["INT", "timestamptz"],
|
|
10
|
+
["INT8", "timestamptz"]
|
|
11
|
+
];
|
|
12
|
+
const needUsing = [
|
|
13
|
+
["DATETIME", "varchar"],
|
|
14
|
+
["INT", "varchar"],
|
|
15
|
+
["INT8", "varchar"]
|
|
16
|
+
];
|
|
17
|
+
const types = { int2: "SMALLINT", int4: "INTEGER", int8: "BIGINT", varchar: "VARCHAR" };
|
|
3
18
|
|
|
4
19
|
export class PGDB extends DB {
|
|
5
20
|
private client: PoolClient;
|
|
21
|
+
private indexes: string[];
|
|
6
22
|
private pool: Pool;
|
|
23
|
+
private version: number;
|
|
7
24
|
|
|
8
25
|
constructor(connection: PoolConfig, log: (message: string) => void) {
|
|
9
26
|
super(log);
|
|
@@ -13,6 +30,10 @@ export class PGDB extends DB {
|
|
|
13
30
|
|
|
14
31
|
async connect(): Promise<void> {
|
|
15
32
|
this.client = await this.pool.connect();
|
|
33
|
+
|
|
34
|
+
const res = await this.client.query("SELECT version()");
|
|
35
|
+
|
|
36
|
+
this.version = parseInt(res.rows[0].version.split(" ")[1].split(".")[0], 10);
|
|
16
37
|
}
|
|
17
38
|
|
|
18
39
|
async dropConstraints(table: Table): Promise<void> {
|
|
@@ -50,32 +71,71 @@ export class PGDB extends DB {
|
|
|
50
71
|
}
|
|
51
72
|
}
|
|
52
73
|
|
|
74
|
+
async dropField(tableName: string, fieldName: string): Promise<void> {
|
|
75
|
+
const statement = `ALTER TABLE ${tableName} DROP COLUMN ${fieldName}`;
|
|
76
|
+
|
|
77
|
+
this.log(statement);
|
|
78
|
+
await this.client.query(statement);
|
|
79
|
+
}
|
|
80
|
+
|
|
53
81
|
async dropFields(table: Table): Promise<void> {
|
|
54
82
|
const res = await this.client.query("SELECT attname FROM pg_attribute WHERE attrelid = $1 AND attnum > 0 AND attisdropped = false AND attinhcount = 0", [table.oid]);
|
|
55
83
|
|
|
56
|
-
for(const i in res.rows)
|
|
57
|
-
|
|
58
|
-
const statement = `ALTER TABLE ${table.tableName} DROP COLUMN ${res.rows[i].attname}`;
|
|
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);
|
|
85
|
+
}
|
|
59
86
|
|
|
60
|
-
|
|
61
|
-
|
|
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];
|
|
62
109
|
}
|
|
63
110
|
}
|
|
64
|
-
}
|
|
65
111
|
|
|
66
|
-
|
|
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
|
+
}
|
|
67
119
|
|
|
68
120
|
async end(): Promise<void> {
|
|
69
121
|
await this.pool.end();
|
|
70
122
|
}
|
|
71
123
|
|
|
72
|
-
fieldType(field: Field<
|
|
124
|
+
fieldType(field: Field<unknown, unknown>): string[] {
|
|
73
125
|
const { size, type } = field;
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return "
|
|
126
|
+
let ret;
|
|
127
|
+
|
|
128
|
+
switch(type) {
|
|
129
|
+
case "DATETIME":
|
|
130
|
+
return ["DATETIME", "TIMESTAMP (3) WITH TIME ZONE"];
|
|
131
|
+
case "INT":
|
|
132
|
+
ret = size === 2 ? "SMALLINT" : "INTEGER";
|
|
133
|
+
|
|
134
|
+
return [ret, ret];
|
|
135
|
+
case "INT8":
|
|
136
|
+
return ["BIGINT", "BIGINT"];
|
|
137
|
+
case "VARCHAR":
|
|
138
|
+
return ["VARCHAR", "VARCHAR" + (size ? `(${size})` : "")];
|
|
79
139
|
}
|
|
80
140
|
|
|
81
141
|
throw new Error(`Unknown type: '${type}', '${size}'`);
|
|
@@ -114,19 +174,99 @@ export class PGDB extends DB {
|
|
|
114
174
|
}
|
|
115
175
|
|
|
116
176
|
async syncFields(table: Table): Promise<void> {
|
|
117
|
-
|
|
118
|
-
|
|
177
|
+
const { fields, oid, tableName } = table;
|
|
178
|
+
|
|
179
|
+
for(const field of fields) {
|
|
180
|
+
const { fieldName, notNull, size } = field;
|
|
181
|
+
const defaultValue = field.defaultValue === undefined ? undefined : format("%L", field.defaultValue);
|
|
182
|
+
const [base, type] = this.fieldType(field);
|
|
183
|
+
|
|
119
184
|
const res = await this.client.query(
|
|
120
|
-
|
|
121
|
-
|
|
185
|
+
`SELECT *${
|
|
186
|
+
this.version >= 12 ? ", pg_get_expr(pg_attrdef.adbin, pg_attrdef.adrelid) AS adsrc" : ""
|
|
187
|
+
} 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`,
|
|
188
|
+
[oid, fieldName]
|
|
122
189
|
);
|
|
123
190
|
|
|
191
|
+
const addField = async () => {
|
|
192
|
+
const statement = `ALTER TABLE ${tableName} ADD COLUMN ${fieldName} ${type}`;
|
|
193
|
+
|
|
194
|
+
this.log(statement);
|
|
195
|
+
await this.client.query(statement);
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const dropDefault = async () => {
|
|
199
|
+
const statement = `ALTER TABLE ${tableName} ALTER COLUMN ${fieldName} DROP DEFAULT`;
|
|
200
|
+
|
|
201
|
+
this.log(statement);
|
|
202
|
+
await this.client.query(statement);
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const setDefault = async () => {
|
|
206
|
+
if(defaultValue === undefined) return;
|
|
207
|
+
|
|
208
|
+
const statement = `ALTER TABLE ${tableName} ALTER COLUMN ${fieldName} SET DEFAULT ${defaultValue}`;
|
|
209
|
+
|
|
210
|
+
this.log(statement);
|
|
211
|
+
await this.client.query(statement);
|
|
212
|
+
};
|
|
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
|
+
|
|
124
223
|
if(! res.rowCount) {
|
|
125
|
-
|
|
224
|
+
await addField();
|
|
225
|
+
await setDefault();
|
|
226
|
+
await setNotNull(false);
|
|
227
|
+
} else {
|
|
228
|
+
const { adsrc, attnotnull, atttypmod, typname } = res.rows[0];
|
|
229
|
+
|
|
230
|
+
if(types[typname] !== base || (base === "VARCHAR" && (size ? size + 4 !== atttypmod : atttypmod !== -1))) {
|
|
231
|
+
if(needDrop.filter(([type, name]) => field.type === type && typname === name).length) {
|
|
232
|
+
await this.dropField(tableName, fieldName);
|
|
233
|
+
await addField();
|
|
234
|
+
await setDefault();
|
|
235
|
+
await setNotNull(false);
|
|
236
|
+
} else {
|
|
237
|
+
if(adsrc) dropDefault();
|
|
238
|
+
|
|
239
|
+
const using = needUsing.filter(([type, name]) => field.type === type && typname === name).length ? " USING " + fieldName + "::" + type : "";
|
|
240
|
+
const statement = `ALTER TABLE ${tableName} ALTER COLUMN ${fieldName} TYPE ${type}${using}`;
|
|
241
|
+
|
|
242
|
+
this.log(statement);
|
|
243
|
+
await this.client.query(statement);
|
|
244
|
+
await setDefault();
|
|
245
|
+
await setNotNull(attnotnull);
|
|
246
|
+
}
|
|
247
|
+
} else if(defaultValue === undefined) {
|
|
248
|
+
if(adsrc) dropDefault();
|
|
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(", ")})`;
|
|
126
266
|
|
|
127
267
|
this.log(statement);
|
|
128
268
|
await this.client.query(statement);
|
|
129
|
-
}
|
|
269
|
+
}
|
|
130
270
|
}
|
|
131
271
|
}
|
|
132
272
|
|
package/package.json
CHANGED
|
@@ -2,27 +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
|
-
"pg": "
|
|
7
|
-
"
|
|
5
|
+
"@types/pg": "8.6.1",
|
|
6
|
+
"@types/pg-format": "1.0.2",
|
|
7
|
+
"pg": "8.7.1",
|
|
8
|
+
"pg-format": "1.0.4",
|
|
9
|
+
"sedentary": "0.0.12"
|
|
8
10
|
},
|
|
9
11
|
"description": "The ORM which never needs to migrate - PostgreSQL",
|
|
10
12
|
"devDependencies": {
|
|
11
|
-
"@types/mocha": "
|
|
12
|
-
"@types/node": "
|
|
13
|
+
"@types/mocha": "9.0.0",
|
|
14
|
+
"@types/node": "16.11.6",
|
|
13
15
|
"@types/yamljs": "0.2.31",
|
|
14
|
-
"@typescript-eslint/eslint-plugin": "
|
|
15
|
-
"@typescript-eslint/parser": "
|
|
16
|
-
"eslint": "
|
|
17
|
-
"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",
|
|
18
20
|
"nyc": "15.1.0",
|
|
19
|
-
"prettier": "2.
|
|
20
|
-
"ts-node": "
|
|
21
|
-
"typescript": "4.
|
|
21
|
+
"prettier": "2.4.1",
|
|
22
|
+
"ts-node": "10.4.0",
|
|
23
|
+
"typescript": "4.4.4",
|
|
22
24
|
"yamljs": "0.3.0"
|
|
23
25
|
},
|
|
24
26
|
"engines": {
|
|
25
|
-
"node": ">=
|
|
27
|
+
"node": ">=12.0"
|
|
26
28
|
},
|
|
27
29
|
"homepage": "https://github.com/iccicci/sedentary-pg#readme",
|
|
28
30
|
"keywords": [
|
|
@@ -47,15 +49,15 @@
|
|
|
47
49
|
"readmeFilename": "README.md",
|
|
48
50
|
"repository": "https://github.com/iccicci/sedentary-pg",
|
|
49
51
|
"scripts": {
|
|
50
|
-
"coverage": "nyc -r lcov -r text -r text-summary -r html mocha -r ts-node/register test/*
|
|
52
|
+
"coverage": "nyc -r lcov -r text -r text-summary -r html mocha -r ts-node/register test/*ts",
|
|
51
53
|
"gitignore": "node -r ts-node/register utils.ts gitignore",
|
|
52
54
|
"npmignore": "node -r ts-node/register utils.ts npmignore",
|
|
53
55
|
"packagejson": "node -r ts-node/register utils.ts packagejson",
|
|
54
|
-
"test": "mocha -r ts-node/register test/*
|
|
56
|
+
"test": "mocha -r ts-node/register test/*ts",
|
|
55
57
|
"travis": "node -r ts-node/register utils.ts travis",
|
|
56
58
|
"tsc": "tsc --declaration",
|
|
57
59
|
"version": "node -r ts-node/register utils.ts version"
|
|
58
60
|
},
|
|
59
61
|
"types": "index.d.ts",
|
|
60
|
-
"version": "0.0.
|
|
61
|
-
}
|
|
62
|
+
"version": "0.0.12"
|
|
63
|
+
}
|