sedentary 0.0.15 → 0.0.19
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 +0 -4
- package/index.d.ts +65 -57
- package/index.js +206 -84
- package/lib/db.d.ts +16 -2
- package/lib/db.js +5 -5
- package/lib/minidb.js +75 -52
- package/package.json +13 -7
- package/requirements.txt +2 -0
- package/sedentary-pg/LICENSE +0 -21
- package/sedentary-pg/README.md +0 -34
- package/sedentary-pg/lib/pgdb.ts +0 -340
- package/sedentary-pg/package-lock.json +0 -6768
- package/sedentary-pg/package.json +0 -66
package/lib/minidb.js
CHANGED
|
@@ -21,40 +21,47 @@ class MiniDB extends db_1.DB {
|
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
async dropConstraints(table) {
|
|
24
|
-
const { constraints } = this.body.tables[table.tableName];
|
|
24
|
+
const { constraints } = this.body.tables[table.tableName] || { constraints: { f: {}, u: {} } };
|
|
25
25
|
for (const constraint of Object.keys(constraints.f).sort()) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
const arr = table.constraints.filter(({ constraintName, type }) => constraintName === constraint && type === "f");
|
|
27
|
+
const dbOptions = arr.length ? arr[0].attribute.foreignKey.options : { onDelete: "delete", onUpdate: "delete" };
|
|
28
|
+
const inOptions = constraints.f[constraint].options;
|
|
29
|
+
if (dbOptions.onDelete !== inOptions.onDelete || dbOptions.onUpdate !== inOptions.onUpdate) {
|
|
30
|
+
this.syncLog(`'${table.tableName}': Removing foreign key: '${constraint}'`);
|
|
31
|
+
if (this.sync)
|
|
32
|
+
delete constraints.f[constraint];
|
|
29
33
|
}
|
|
30
34
|
}
|
|
31
35
|
for (const constraint of Object.keys(constraints.u).sort()) {
|
|
32
36
|
if (!table.constraints.filter(({ constraintName, type }) => constraintName === constraint && type === "u").length) {
|
|
33
|
-
this.
|
|
34
|
-
|
|
37
|
+
this.syncLog(`'${table.tableName}': Removing unique constraint from field: '${constraints.u[constraint].on}'`);
|
|
38
|
+
if (this.sync)
|
|
39
|
+
delete constraints.u[constraint];
|
|
35
40
|
}
|
|
36
41
|
}
|
|
37
42
|
await this.save();
|
|
38
43
|
return [];
|
|
39
44
|
}
|
|
40
45
|
async dropFields(table) {
|
|
41
|
-
const { fields } = this.body.tables[table.tableName];
|
|
42
|
-
for (const attribute
|
|
46
|
+
const { fields } = this.body.tables[table.tableName] || { fields: {} };
|
|
47
|
+
for (const attribute of Object.keys(fields).sort()) {
|
|
43
48
|
if (!table.findField(attribute)) {
|
|
44
|
-
this.
|
|
45
|
-
|
|
49
|
+
this.syncLog(`'${table.tableName}': Removing field: '${attribute}'`);
|
|
50
|
+
if (this.sync)
|
|
51
|
+
delete fields[attribute];
|
|
46
52
|
}
|
|
47
53
|
}
|
|
48
54
|
await this.save();
|
|
49
55
|
}
|
|
50
56
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
51
57
|
async dropIndexes(table, constraintIndexes) {
|
|
52
|
-
const { indexes } = this.body.tables[table.tableName];
|
|
53
|
-
for (const name
|
|
58
|
+
const { indexes } = this.body.tables[table.tableName] || { indexes: {} };
|
|
59
|
+
for (const name of Object.keys(indexes).sort()) {
|
|
54
60
|
const index = table.indexes.filter(_ => _.indexName === name);
|
|
55
61
|
if (index.length === 0 || !this.indexesEq(indexes[name], index[0])) {
|
|
56
|
-
this.
|
|
57
|
-
|
|
62
|
+
this.syncLog(`'${table.tableName}': Removing index: '${name}'`);
|
|
63
|
+
if (this.sync)
|
|
64
|
+
delete indexes[name];
|
|
58
65
|
}
|
|
59
66
|
}
|
|
60
67
|
await this.save();
|
|
@@ -64,72 +71,84 @@ class MiniDB extends db_1.DB {
|
|
|
64
71
|
await writeFile(this.file, JSON.stringify(this.body));
|
|
65
72
|
}
|
|
66
73
|
async syncConstraints(table) {
|
|
67
|
-
const { constraints } = this.body.tables[table.tableName];
|
|
74
|
+
const { constraints } = this.body.tables[table.tableName] || { constraints: { f: {}, u: {} } };
|
|
68
75
|
for (const constraint of table.constraints) {
|
|
69
|
-
const { constraintName, type } = constraint;
|
|
70
|
-
const { fieldName, foreignKey } = constraint.attribute;
|
|
76
|
+
const { attribute, constraintName, type } = constraint;
|
|
71
77
|
if (!constraints[type][constraintName]) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
if (type === "f") {
|
|
79
|
+
const { fieldName, options, tableName } = attribute.foreignKey;
|
|
80
|
+
const onDelete = options.onDelete !== "no action" ? ` on delete ${options.onDelete}` : "";
|
|
81
|
+
const onUpdate = options.onUpdate !== "no action" ? ` on update ${options.onUpdate}` : "";
|
|
82
|
+
this.syncLog(`'${table.tableName}': Adding foreign key '${constraint.constraintName}' on field: '${attribute.fieldName}' references '${tableName}(${fieldName})'${onDelete}${onUpdate}`);
|
|
83
|
+
if (this.sync)
|
|
84
|
+
constraints[type][constraintName] = { on: attribute.fieldName, options, fieldName, tableName };
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
this.syncLog(`'${table.tableName}': Adding unique constraint on field: '${attribute.fieldName}'`);
|
|
88
|
+
if (this.sync)
|
|
89
|
+
constraints[type][constraintName] = { on: attribute.fieldName };
|
|
81
90
|
}
|
|
82
91
|
}
|
|
83
92
|
}
|
|
84
93
|
await this.save();
|
|
85
94
|
}
|
|
86
95
|
async syncIndexes(table) {
|
|
87
|
-
const { indexes } = this.body.tables[table.tableName];
|
|
96
|
+
const { indexes } = this.body.tables[table.tableName] || { indexes: {} };
|
|
88
97
|
for (const index of table.indexes) {
|
|
89
98
|
const { indexName } = index;
|
|
90
99
|
if (!(indexName in indexes)) {
|
|
91
|
-
this.
|
|
92
|
-
|
|
100
|
+
this.syncLog(`'${table.tableName}': Adding index: '${indexName}' on (${index.fields.map(_ => `'${_}'`).join(", ")}) type '${index.type}'${index.unique ? " unique" : ""}`);
|
|
101
|
+
if (this.sync)
|
|
102
|
+
indexes[indexName] = index;
|
|
93
103
|
}
|
|
94
104
|
}
|
|
95
105
|
await this.save();
|
|
96
106
|
}
|
|
97
107
|
async syncFields(table) {
|
|
98
108
|
for (const attribute of table.attributes) {
|
|
99
|
-
const { fields } = this.body.tables[table.tableName];
|
|
109
|
+
const { fields } = this.body.tables[table.tableName] || { fields: {} };
|
|
100
110
|
const { defaultValue, fieldName, notNull, size, type } = attribute;
|
|
101
111
|
let field = fields[fieldName];
|
|
102
112
|
if (!field) {
|
|
103
|
-
this.
|
|
104
|
-
|
|
113
|
+
this.syncLog(`'${table.tableName}': Adding field: '${fieldName}' '${type}' '${size || ""}'`);
|
|
114
|
+
if (this.sync)
|
|
115
|
+
field = fields[fieldName] = { size, type };
|
|
116
|
+
else
|
|
117
|
+
field = {};
|
|
105
118
|
}
|
|
106
119
|
if (field.size !== size || field.type !== type) {
|
|
107
|
-
this.
|
|
108
|
-
|
|
120
|
+
this.syncLog(`'${table.tableName}': Changing field type: '${fieldName}' '${type}' '${size || ""}'`);
|
|
121
|
+
if (this.sync)
|
|
122
|
+
field = fields[fieldName] = Object.assign(Object.assign({}, field), { size, type });
|
|
109
123
|
}
|
|
110
124
|
if (field.default) {
|
|
111
125
|
if (!defaultValue) {
|
|
112
|
-
this.
|
|
113
|
-
|
|
126
|
+
this.syncLog(`'${table.tableName}': Dropping default value for field: '${fieldName}'`);
|
|
127
|
+
if (this.sync)
|
|
128
|
+
delete field.default;
|
|
114
129
|
}
|
|
115
130
|
else if (field.default !== defaultValue) {
|
|
116
|
-
this.
|
|
117
|
-
|
|
131
|
+
this.syncLog(`'${table.tableName}': Changing default value to '${defaultValue}' for field: '${fieldName}'`);
|
|
132
|
+
if (this.sync)
|
|
133
|
+
field.default = defaultValue;
|
|
118
134
|
}
|
|
119
135
|
}
|
|
120
136
|
else if (defaultValue) {
|
|
121
|
-
this.
|
|
122
|
-
|
|
137
|
+
this.syncLog(`'${table.tableName}': Setting default value '${defaultValue instanceof Date ? defaultValue.toISOString() : defaultValue}' for field: '${fieldName}'`);
|
|
138
|
+
if (this.sync)
|
|
139
|
+
field.default = defaultValue;
|
|
123
140
|
}
|
|
124
141
|
if (field.notNull) {
|
|
125
142
|
if (!notNull) {
|
|
126
|
-
this.
|
|
127
|
-
|
|
143
|
+
this.syncLog(`'${table.tableName}': Dropping not null for field: '${fieldName}'`);
|
|
144
|
+
if (this.sync)
|
|
145
|
+
delete field.notNull;
|
|
128
146
|
}
|
|
129
147
|
}
|
|
130
148
|
else if (notNull) {
|
|
131
|
-
this.
|
|
132
|
-
|
|
149
|
+
this.syncLog(`'${table.tableName}': Setting not null for field: '${fieldName}'`);
|
|
150
|
+
if (this.sync)
|
|
151
|
+
field.notNull = true;
|
|
133
152
|
}
|
|
134
153
|
}
|
|
135
154
|
await this.save();
|
|
@@ -145,20 +164,24 @@ class MiniDB extends db_1.DB {
|
|
|
145
164
|
}
|
|
146
165
|
else if (!this.body.tables[table.tableName].parent)
|
|
147
166
|
return;
|
|
148
|
-
this.
|
|
149
|
-
|
|
167
|
+
this.syncLog(`Removing table: '${table.tableName}'`);
|
|
168
|
+
if (this.sync)
|
|
169
|
+
delete this.body.tables[table.tableName];
|
|
150
170
|
})();
|
|
151
171
|
}
|
|
152
172
|
if (!this.body.tables[table.tableName]) {
|
|
153
|
-
this.
|
|
154
|
-
this.
|
|
173
|
+
this.syncLog(`Adding table: '${table.tableName}'`);
|
|
174
|
+
if (this.sync)
|
|
175
|
+
this.body.tables[table.tableName] = { constraints: { f: {}, u: {} }, fields: {}, indexes: {} };
|
|
155
176
|
if (table.parent) {
|
|
156
|
-
this.
|
|
157
|
-
this.
|
|
177
|
+
this.syncLog(`Setting parent: '${table.parent.tableName}' - to table: '${table.tableName}'`);
|
|
178
|
+
if (this.sync)
|
|
179
|
+
this.body.tables[table.tableName].parent = table.parent.tableName;
|
|
158
180
|
}
|
|
159
181
|
if (table.autoIncrement && !this.body.next[table.tableName]) {
|
|
160
|
-
this.
|
|
161
|
-
this.
|
|
182
|
+
this.syncLog(`Setting auto increment: '${table.tableName}'`);
|
|
183
|
+
if (this.sync)
|
|
184
|
+
this.body.next[table.tableName] = 1;
|
|
162
185
|
}
|
|
163
186
|
}
|
|
164
187
|
await this.save();
|
package/package.json
CHANGED
|
@@ -5,16 +5,17 @@
|
|
|
5
5
|
"description": "The ORM which never needs to migrate",
|
|
6
6
|
"devDependencies": {
|
|
7
7
|
"@types/mocha": "9.0.0",
|
|
8
|
-
"@types/node": "
|
|
8
|
+
"@types/node": "17.0.0",
|
|
9
9
|
"@types/yamljs": "0.2.31",
|
|
10
|
-
"@typescript-eslint/eslint-plugin": "5.
|
|
11
|
-
"@typescript-eslint/parser": "5.
|
|
12
|
-
"eslint": "8.
|
|
10
|
+
"@typescript-eslint/eslint-plugin": "5.7.0",
|
|
11
|
+
"@typescript-eslint/parser": "5.7.0",
|
|
12
|
+
"eslint": "8.5.0",
|
|
13
13
|
"mocha": "9.1.3",
|
|
14
14
|
"nyc": "15.1.0",
|
|
15
|
-
"prettier": "2.5.
|
|
15
|
+
"prettier": "2.5.1",
|
|
16
16
|
"ts-node": "10.4.0",
|
|
17
|
-
"
|
|
17
|
+
"tsd": "0.19.0",
|
|
18
|
+
"typescript": "4.5.4",
|
|
18
19
|
"yamljs": "0.3.0"
|
|
19
20
|
},
|
|
20
21
|
"engines": {
|
|
@@ -55,6 +56,11 @@
|
|
|
55
56
|
"tsc": "tsc --declaration",
|
|
56
57
|
"version": "node -r ts-node/register utils.ts version"
|
|
57
58
|
},
|
|
59
|
+
"tsd": {
|
|
60
|
+
"compilerOptions": {
|
|
61
|
+
"strict": false
|
|
62
|
+
}
|
|
63
|
+
},
|
|
58
64
|
"types": "index.d.ts",
|
|
59
|
-
"version": "0.0.
|
|
65
|
+
"version": "0.0.19"
|
|
60
66
|
}
|
package/requirements.txt
ADDED
package/sedentary-pg/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2017 Daniele Ricci
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
package/sedentary-pg/README.md
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# sedentary-pg
|
|
2
|
-
|
|
3
|
-
[![Build Status][travis-badge]][travis-url]
|
|
4
|
-
[![Code Climate][code-badge]][code-url]
|
|
5
|
-
[![Test Coverage][cover-badge]][code-url]
|
|
6
|
-
|
|
7
|
-
[![NPM version][npm-badge]][npm-url]
|
|
8
|
-
[![NPM downloads][npm-downloads-badge]][npm-url]
|
|
9
|
-
[![Stars][stars-badge]][github-url]
|
|
10
|
-
|
|
11
|
-
[![Types][types-badge]][npm-url]
|
|
12
|
-
[![Dependents][deps-badge]][npm-url]
|
|
13
|
-
[![Donate][donate-badge]][donate-url]
|
|
14
|
-
|
|
15
|
-
[code-badge]: https://codeclimate.com/github/iccicci/sedentary-pg/badges/gpa.svg
|
|
16
|
-
[code-url]: https://codeclimate.com/github/iccicci/sedentary-pg
|
|
17
|
-
[cover-badge]: https://codeclimate.com/github/iccicci/sedentary-pg/badges/coverage.svg
|
|
18
|
-
[deps-badge]: https://badgen.net/npm/dependents/sedentary-pg?icon=npm&cache=300
|
|
19
|
-
[donate-badge]: https://badgen.net/badge/donate/bitcoin?icon=bitcoin&cache=300
|
|
20
|
-
[donate-url]: https://blockchain.info/address/1Md9WFAHrXTb3yPBwQWmUfv2RmzrtbHioB
|
|
21
|
-
[github-url]: https://github.com/iccicci/sedentary-pg
|
|
22
|
-
[npm-downloads-badge]: https://badgen.net/npm/dw/sedentary-pg?icon=npm&cache=300
|
|
23
|
-
[npm-badge]: https://badgen.net/npm/v/sedentary-pg?color=green&icon=npm&cache=300
|
|
24
|
-
[npm-url]: https://www.npmjs.com/package/sedentary-pg
|
|
25
|
-
[stars-badge]: https://badgen.net/github/stars/iccicci/sedentary-pg?icon=github&cache=300
|
|
26
|
-
[travis-badge]: https://badgen.net/travis/iccicci/sedentary-pg?icon=travis&cache=300
|
|
27
|
-
[travis-url]: https://app.travis-ci.com/github/iccicci/sedentary-pg
|
|
28
|
-
[types-badge]: https://badgen.net/npm/types/sedentary-pg?color=green&icon=typescript&cache=300
|
|
29
|
-
|
|
30
|
-
# under development
|
|
31
|
-
|
|
32
|
-
https://www.postgresql.org/support/versioning/
|
|
33
|
-
|
|
34
|
-
https://bucardo.org/postgres_all_versions.html
|
package/sedentary-pg/lib/pgdb.ts
DELETED
|
@@ -1,340 +0,0 @@
|
|
|
1
|
-
import { Pool, PoolClient, PoolConfig } from "pg";
|
|
2
|
-
import format from "pg-format";
|
|
3
|
-
import { Attribute, DB, Index, Natural, 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" };
|
|
18
|
-
|
|
19
|
-
export class PGDB extends DB {
|
|
20
|
-
private client: PoolClient;
|
|
21
|
-
private indexes: string[];
|
|
22
|
-
private pool: Pool;
|
|
23
|
-
private version: number;
|
|
24
|
-
|
|
25
|
-
constructor(connection: PoolConfig, log: (message: string) => void) {
|
|
26
|
-
super(log);
|
|
27
|
-
|
|
28
|
-
this.pool = new Pool(connection);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async connect(): Promise<void> {
|
|
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);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async dropConstraints(table: Table): Promise<number[]> {
|
|
40
|
-
const indexes: number[] = [];
|
|
41
|
-
const res = await this.client.query("SELECT * FROM pg_constraint WHERE conrelid = $1 ORDER BY conname", [table.oid]);
|
|
42
|
-
|
|
43
|
-
for(const row of res.rows) {
|
|
44
|
-
const constraint = table.constraints.filter(_ => _.constraintName === row.conname);
|
|
45
|
-
|
|
46
|
-
if(constraint.length === 0) {
|
|
47
|
-
const statement = `ALTER TABLE ${table.tableName} DROP CONSTRAINT ${row.conname} CASCADE`;
|
|
48
|
-
|
|
49
|
-
this.log(statement);
|
|
50
|
-
await this.client.query(statement);
|
|
51
|
-
} else indexes.push(row.conindid);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return indexes;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
async dropField(tableName: string, fieldName: string): Promise<void> {
|
|
58
|
-
const statement = `ALTER TABLE ${tableName} DROP COLUMN ${fieldName}`;
|
|
59
|
-
|
|
60
|
-
this.log(statement);
|
|
61
|
-
await this.client.query(statement);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
async dropFields(table: Table): Promise<void> {
|
|
65
|
-
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]);
|
|
66
|
-
|
|
67
|
-
for(const i in res.rows) if(! table.findField(res.rows[i].attname)) await this.dropField(table.tableName, res.rows[i].attname);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async dropIndexes(table: Table, constraintIndexes: number[]): Promise<void> {
|
|
71
|
-
const { indexes, oid } = table;
|
|
72
|
-
const iobject: { [key: string]: Index } = {};
|
|
73
|
-
const res = await this.client.query(
|
|
74
|
-
"SELECT amname, attname, indexrelid, 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",
|
|
75
|
-
[oid]
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
for(const row of res.rows) {
|
|
79
|
-
const { amname, attname, indexrelid, indisunique, relname } = row;
|
|
80
|
-
|
|
81
|
-
if(! constraintIndexes.includes(indexrelid)) {
|
|
82
|
-
if(iobject[relname]) iobject[relname].fields.push(attname);
|
|
83
|
-
else iobject[relname] = { fields: [attname], indexName: relname, type: amname, unique: indisunique };
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
this.indexes = [];
|
|
88
|
-
for(const index of indexes) {
|
|
89
|
-
const { indexName } = index;
|
|
90
|
-
|
|
91
|
-
if(iobject[indexName] && this.indexesEq(index, iobject[indexName])) {
|
|
92
|
-
this.indexes.push(indexName);
|
|
93
|
-
delete iobject[indexName];
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
for(const index of Object.keys(iobject).sort()) {
|
|
98
|
-
const statement = `DROP INDEX ${index}`;
|
|
99
|
-
|
|
100
|
-
this.log(statement);
|
|
101
|
-
await this.client.query(statement);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
async end(): Promise<void> {
|
|
106
|
-
await this.pool.end();
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
fieldType(attribute: Attribute<Natural, unknown>): string[] {
|
|
110
|
-
const { size, type } = attribute;
|
|
111
|
-
let ret;
|
|
112
|
-
|
|
113
|
-
switch(type) {
|
|
114
|
-
case "DATETIME":
|
|
115
|
-
return ["DATETIME", "TIMESTAMP (3) WITH TIME ZONE"];
|
|
116
|
-
case "INT":
|
|
117
|
-
ret = size === 2 ? "SMALLINT" : "INTEGER";
|
|
118
|
-
|
|
119
|
-
return [ret, ret];
|
|
120
|
-
case "INT8":
|
|
121
|
-
return ["BIGINT", "BIGINT"];
|
|
122
|
-
case "VARCHAR":
|
|
123
|
-
return ["VARCHAR", "VARCHAR" + (size ? `(${size})` : "")];
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
throw new Error(`Unknown type: '${type}', '${size}'`);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
async syncDataBase(): Promise<void> {
|
|
130
|
-
let err: Error;
|
|
131
|
-
|
|
132
|
-
try {
|
|
133
|
-
await super.syncDataBase();
|
|
134
|
-
} catch(e) {
|
|
135
|
-
err = e;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
this.client.release();
|
|
139
|
-
|
|
140
|
-
if(err) throw err;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
async syncConstraints(table: Table): Promise<void> {
|
|
144
|
-
for(const constraint of table.constraints) {
|
|
145
|
-
const { attribute, constraintName, type } = constraint;
|
|
146
|
-
const res = await this.client.query("SELECT attname FROM pg_attribute, pg_constraint WHERE attrelid = $1 AND conrelid = $1 AND attnum = conkey[1] AND attname = $2", [
|
|
147
|
-
table.oid,
|
|
148
|
-
attribute.fieldName
|
|
149
|
-
]);
|
|
150
|
-
|
|
151
|
-
if(! res.rowCount) {
|
|
152
|
-
let query: string;
|
|
153
|
-
|
|
154
|
-
switch(type) {
|
|
155
|
-
case "f":
|
|
156
|
-
query = `FOREIGN KEY (${attribute.fieldName}) REFERENCES ${attribute.foreignKey.tableName}(${attribute.foreignKey.fieldName})`;
|
|
157
|
-
break;
|
|
158
|
-
case "u":
|
|
159
|
-
query = `UNIQUE(${attribute.fieldName})`;
|
|
160
|
-
break;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const statement = `ALTER TABLE ${table.tableName} ADD CONSTRAINT ${constraintName} ${query}`;
|
|
164
|
-
|
|
165
|
-
this.log(statement);
|
|
166
|
-
await this.client.query(statement);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
async syncFields(table: Table): Promise<void> {
|
|
172
|
-
const { attributes, oid, tableName } = table;
|
|
173
|
-
|
|
174
|
-
for(const attribute of attributes) {
|
|
175
|
-
const { fieldName, notNull, size } = attribute;
|
|
176
|
-
const defaultValue = attribute.defaultValue === undefined ? undefined : format("%L", attribute.defaultValue);
|
|
177
|
-
const [base, type] = this.fieldType(attribute);
|
|
178
|
-
const adsrc = this.version >= 12 ? "pg_get_expr(pg_attrdef.adbin, pg_attrdef.adrelid) AS adsrc" : "adsrc";
|
|
179
|
-
|
|
180
|
-
const res = await this.client.query(
|
|
181
|
-
`SELECT attnotnull, atttypmod, typname, ${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`,
|
|
182
|
-
[oid, fieldName]
|
|
183
|
-
);
|
|
184
|
-
|
|
185
|
-
const addField = async () => {
|
|
186
|
-
const statement = `ALTER TABLE ${tableName} ADD COLUMN ${fieldName} ${type}`;
|
|
187
|
-
|
|
188
|
-
this.log(statement);
|
|
189
|
-
await this.client.query(statement);
|
|
190
|
-
};
|
|
191
|
-
|
|
192
|
-
const dropDefault = async () => {
|
|
193
|
-
const statement = `ALTER TABLE ${tableName} ALTER COLUMN ${fieldName} DROP DEFAULT`;
|
|
194
|
-
|
|
195
|
-
this.log(statement);
|
|
196
|
-
await this.client.query(statement);
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
const setNotNull = async (isNull: boolean) => {
|
|
200
|
-
if(isNull === notNull) return;
|
|
201
|
-
|
|
202
|
-
const statement = `ALTER TABLE ${tableName} ALTER COLUMN ${fieldName} ${notNull ? "SET" : "DROP"} NOT NULL`;
|
|
203
|
-
|
|
204
|
-
this.log(statement);
|
|
205
|
-
await this.client.query(statement);
|
|
206
|
-
};
|
|
207
|
-
|
|
208
|
-
const setDefault = async (isNull: boolean) => {
|
|
209
|
-
if(defaultValue !== undefined) {
|
|
210
|
-
let statement = `ALTER TABLE ${tableName} ALTER COLUMN ${fieldName} SET DEFAULT ${defaultValue}`;
|
|
211
|
-
|
|
212
|
-
this.log(statement);
|
|
213
|
-
await this.client.query(statement);
|
|
214
|
-
|
|
215
|
-
if(isNull) {
|
|
216
|
-
statement = `UPDATE ${tableName} SET ${fieldName} = ${defaultValue} WHERE ${fieldName} IS NULL`;
|
|
217
|
-
|
|
218
|
-
this.log(statement);
|
|
219
|
-
this.client.query(statement);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
await setNotNull(isNull);
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
if(! res.rowCount) {
|
|
227
|
-
await addField();
|
|
228
|
-
await setDefault(false);
|
|
229
|
-
} else {
|
|
230
|
-
const { adsrc, attnotnull, atttypmod, typname } = res.rows[0];
|
|
231
|
-
|
|
232
|
-
if(types[typname] !== base || (base === "VARCHAR" && (size ? size + 4 !== atttypmod : atttypmod !== -1))) {
|
|
233
|
-
if(needDrop.filter(([type, name]) => attribute.type === type && typname === name).length) {
|
|
234
|
-
await this.dropField(tableName, fieldName);
|
|
235
|
-
await addField();
|
|
236
|
-
await setDefault(false);
|
|
237
|
-
} else {
|
|
238
|
-
if(adsrc) dropDefault();
|
|
239
|
-
|
|
240
|
-
const using = needUsing.filter(([type, name]) => attribute.type === type && typname === name).length ? " USING " + fieldName + "::" + type : "";
|
|
241
|
-
const statement = `ALTER TABLE ${tableName} ALTER COLUMN ${fieldName} TYPE ${type}${using}`;
|
|
242
|
-
|
|
243
|
-
this.log(statement);
|
|
244
|
-
await this.client.query(statement);
|
|
245
|
-
await setDefault(attnotnull);
|
|
246
|
-
}
|
|
247
|
-
} else if(defaultValue === undefined) {
|
|
248
|
-
if(adsrc) dropDefault();
|
|
249
|
-
await setNotNull(attnotnull);
|
|
250
|
-
} else if(! adsrc || adsrc.split("::")[0] !== defaultValue) await setDefault(attnotnull);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
async syncIndexes(table: Table): Promise<void> {
|
|
256
|
-
const { indexes, tableName } = table;
|
|
257
|
-
|
|
258
|
-
for(const index of indexes) {
|
|
259
|
-
const { fields, indexName, type, unique } = index;
|
|
260
|
-
|
|
261
|
-
if(! this.indexes.includes(indexName)) {
|
|
262
|
-
const statement = `CREATE${unique ? " UNIQUE" : ""} INDEX ${indexName} ON ${tableName} USING ${type} (${fields.join(", ")})`;
|
|
263
|
-
|
|
264
|
-
this.log(statement);
|
|
265
|
-
await this.client.query(statement);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
async syncSequence(table: Table): Promise<void> {
|
|
271
|
-
if(! table.autoIncrementOwn) return;
|
|
272
|
-
|
|
273
|
-
const statement = `ALTER SEQUENCE ${table.tableName}_id_seq OWNED BY ${table.tableName}.id`;
|
|
274
|
-
|
|
275
|
-
this.log(statement);
|
|
276
|
-
await this.client.query(statement);
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
async syncTable(table: Table): Promise<void> {
|
|
280
|
-
if(table.autoIncrement) {
|
|
281
|
-
await (async () => {
|
|
282
|
-
try {
|
|
283
|
-
await this.client.query(`SELECT currval('${table.tableName}_id_seq')`);
|
|
284
|
-
} catch(e) {
|
|
285
|
-
if(e.code === "55000") return;
|
|
286
|
-
if(e.code === "42P01") {
|
|
287
|
-
const statement = `CREATE SEQUENCE ${table.tableName}_id_seq`;
|
|
288
|
-
|
|
289
|
-
this.log(statement);
|
|
290
|
-
await this.client.query(statement);
|
|
291
|
-
table.autoIncrementOwn = true;
|
|
292
|
-
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
throw e;
|
|
297
|
-
}
|
|
298
|
-
})();
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
let create: boolean;
|
|
302
|
-
const resTable = await this.client.query("SELECT oid FROM pg_class WHERE relname = $1", [table.tableName]);
|
|
303
|
-
|
|
304
|
-
if(resTable.rowCount) {
|
|
305
|
-
table.oid = resTable.rows[0].oid;
|
|
306
|
-
|
|
307
|
-
let drop: boolean;
|
|
308
|
-
const resParent = await this.client.query("SELECT inhparent FROM pg_inherits WHERE inhrelid = $1", [table.oid]);
|
|
309
|
-
|
|
310
|
-
if(resParent.rowCount) {
|
|
311
|
-
if(! table.parent) drop = true;
|
|
312
|
-
else if(this.findTable(table.parent.tableName).oid === resParent.rows[0].inhparent) return;
|
|
313
|
-
|
|
314
|
-
drop = true;
|
|
315
|
-
} else if(table.parent) drop = true;
|
|
316
|
-
|
|
317
|
-
if(drop) {
|
|
318
|
-
const statement = `DROP TABLE ${table.tableName} CASCADE`;
|
|
319
|
-
|
|
320
|
-
create = true;
|
|
321
|
-
this.log(statement);
|
|
322
|
-
await this.client.query(statement);
|
|
323
|
-
}
|
|
324
|
-
} else create = true;
|
|
325
|
-
|
|
326
|
-
if(create) {
|
|
327
|
-
const parent = table.parent ? ` INHERITS (${table.parent.tableName})` : "";
|
|
328
|
-
const statement = `CREATE TABLE ${table.tableName} ()${parent}`;
|
|
329
|
-
|
|
330
|
-
this.log(statement);
|
|
331
|
-
await this.client.query(statement);
|
|
332
|
-
|
|
333
|
-
const resTable = await this.client.query("SELECT oid FROM pg_class WHERE relname = $1", [table.tableName]);
|
|
334
|
-
|
|
335
|
-
table.oid = resTable.rows[0].oid;
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// farray[0].defaultValue = "nextval('" + tname + "_id_seq'::regclass)";
|