sedentary-pg 0.0.22 → 0.0.23

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.
File without changes
File without changes
package/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { EntryBase, ForeignKeyOptions, Natural, Sedentary, SedentaryOptions, Type } from "sedentary";
2
- import { Attribute } from "sedentary/lib/db";
2
+ import { Attribute } from "sedentary/db";
3
3
  import { PoolConfig } from "pg";
4
4
  export { EntryBase, SedentaryOptions, Type } from "sedentary";
5
5
  export declare class SedentaryPG extends Sedentary {
package/index.js CHANGED
@@ -2,13 +2,13 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Package = exports.SedentaryPG = exports.Type = exports.EntryBase = void 0;
4
4
  const sedentary_1 = require("sedentary");
5
- const pgdb_1 = require("./lib/pgdb");
5
+ const pgdb_1 = require("./pgdb");
6
6
  var sedentary_2 = require("sedentary");
7
7
  Object.defineProperty(exports, "EntryBase", { enumerable: true, get: function () { return sedentary_2.EntryBase; } });
8
8
  Object.defineProperty(exports, "Type", { enumerable: true, get: function () { return sedentary_2.Type; } });
9
9
  class SedentaryPG extends sedentary_1.Sedentary {
10
10
  constructor(connection, options) {
11
- super("", options);
11
+ super(options);
12
12
  if (!(connection instanceof Object))
13
13
  throw new Error("SedentaryPG.constructor: 'connection' argument: Wrong type, expected 'Object'");
14
14
  this.db = new pgdb_1.PGDB(connection, this.log);
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "dependencies": {
9
9
  "pg": "8.7.1",
10
10
  "pg-format": "1.0.4",
11
- "sedentary": "0.0.22"
11
+ "sedentary": "0.0.23"
12
12
  },
13
13
  "description": "The ORM which never needs to migrate - PostgreSQL",
14
14
  "devDependencies": {
@@ -84,5 +84,5 @@
84
84
  }
85
85
  },
86
86
  "types": "index.d.ts",
87
- "version": "0.0.22"
87
+ "version": "0.0.23"
88
88
  }
@@ -1,5 +1,5 @@
1
- import { PoolConfig } from "pg";
2
- import { Attribute, DB, Natural, Table } from "sedentary/lib/db";
1
+ import { PoolClient, PoolConfig } from "pg";
2
+ import { Attribute, DB, Natural, Table, Transaction } from "sedentary/db";
3
3
  export declare class PGDB extends DB {
4
4
  private client;
5
5
  private indexes;
@@ -7,16 +7,26 @@ export declare class PGDB extends DB {
7
7
  private version;
8
8
  constructor(connection: PoolConfig, log: (message: string) => void);
9
9
  connect(): Promise<void>;
10
+ end(): Promise<void>;
11
+ defaultNeq(src: string, value: Natural): boolean;
12
+ escape(value: Natural): string;
13
+ fill(attributes: Attribute<Natural, unknown>[], row: Record<string, Natural>, entity: Record<string, Natural>): void;
14
+ save(tableName: string, attributes: Attribute<Natural, unknown>[]): (this: Record<string, Natural> & {
15
+ loaded?: Record<string, unknown>;
16
+ tx?: TransactionPG;
17
+ }) => Promise<boolean>;
10
18
  dropConstraints(table: Table): Promise<number[]>;
11
19
  dropField(tableName: string, fieldName: string): Promise<void>;
12
20
  dropFields(table: Table): Promise<void>;
13
21
  dropIndexes(table: Table, constraintIndexes: number[]): Promise<void>;
14
- end(): Promise<void>;
15
- fieldType(attribute: Attribute<Natural, unknown>): string[];
16
- syncDataBase(): Promise<void>;
17
22
  syncConstraints(table: Table): Promise<void>;
23
+ fieldType(attribute: Attribute<Natural, unknown>): string[];
18
24
  syncFields(table: Table): Promise<void>;
19
25
  syncIndexes(table: Table): Promise<void>;
20
26
  syncSequence(table: Table): Promise<void>;
21
27
  syncTable(table: Table): Promise<void>;
22
28
  }
29
+ declare class TransactionPG extends Transaction {
30
+ client: PoolClient;
31
+ }
32
+ export {};
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.PGDB = void 0;
7
7
  const pg_1 = require("pg");
8
8
  const pg_format_1 = __importDefault(require("pg-format"));
9
- const db_1 = require("sedentary/lib/db");
9
+ const db_1 = require("sedentary/db");
10
10
  const adsrc_1 = require("./adsrc");
11
11
  const needDrop = [
12
12
  ["DATETIME", "int2"],
@@ -20,7 +20,7 @@ const needUsing = [
20
20
  ["INT", "varchar"],
21
21
  ["INT8", "varchar"]
22
22
  ];
23
- const types = { int2: "SMALLINT", int4: "INTEGER", int8: "BIGINT", varchar: "VARCHAR" };
23
+ const types = { int2: "SMALLINT", int4: "INTEGER", int8: "BIGINT", timestamptz: "DATETIME", varchar: "VARCHAR" };
24
24
  const actions = { cascade: "c", "no action": "a", restrict: "r", "set default": "d", "set null": "n" };
25
25
  class PGDB extends db_1.DB {
26
26
  constructor(connection, log) {
@@ -35,6 +35,70 @@ class PGDB extends db_1.DB {
35
35
  const res = await this.client.query("SELECT version()");
36
36
  this.version = parseInt(res.rows[0].version.split(" ")[1].split(".")[0], 10);
37
37
  }
38
+ async end() {
39
+ this.client.release();
40
+ await this.pool.end();
41
+ }
42
+ defaultNeq(src, value) {
43
+ if (src === value)
44
+ return false;
45
+ return src.split("::")[0] !== value;
46
+ }
47
+ escape(value) {
48
+ if (value === null || value === undefined)
49
+ throw new Error("SedentaryPG: Can't escape null nor undefined values; use the 'IS NULL' operator instead");
50
+ const type = typeof value;
51
+ if (type === "number" || type === "boolean")
52
+ return value.toString();
53
+ if (type === "string")
54
+ return (0, pg_format_1.default)("%L", value);
55
+ if (value instanceof Date)
56
+ return (0, pg_format_1.default)("%L", value).replace(/\.\d\d\d\+/, "+");
57
+ return (0, pg_format_1.default)("%L", JSON.stringify(value));
58
+ }
59
+ fill(attributes, row, entity) {
60
+ for (const attribute of attributes)
61
+ entity[attribute.attributeName] = row[attribute.fieldName];
62
+ }
63
+ save(tableName, attributes) {
64
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
65
+ const self = this;
66
+ return async function () {
67
+ const client = this.tx ? this.tx.client : await self.pool.connect();
68
+ if (!this.loaded) {
69
+ const fields = [];
70
+ const values = [];
71
+ for (const attribute of attributes) {
72
+ const value = this[attribute.attributeName];
73
+ if (value !== null && value !== undefined) {
74
+ fields.push(attribute.fieldName);
75
+ values.push(self.escape(this[attribute.attributeName]));
76
+ }
77
+ }
78
+ const query = fields.length ? `INSERT INTO ${tableName} (${fields.join(",")}) VALUES (${values.join(",")})` : `INSERT INTO ${tableName} DEFAULT VALUES`;
79
+ try {
80
+ self.log(query);
81
+ self.fill(attributes, (await client.query(query + " RETURNING *")).rows[0], this);
82
+ }
83
+ finally {
84
+ if (!this.tx)
85
+ client.release();
86
+ }
87
+ return true;
88
+ }
89
+ let changed = false;
90
+ const { loaded } = this;
91
+ for (const key in this) {
92
+ if (typeof this[key] === "object") {
93
+ if (JSON.stringify(this[key]) !== JSON.stringify(loaded[key]))
94
+ changed = true;
95
+ }
96
+ else if (this[key] !== loaded[key])
97
+ changed = true;
98
+ }
99
+ return Promise.resolve(changed);
100
+ };
101
+ }
38
102
  async dropConstraints(table) {
39
103
  const indexes = [];
40
104
  const res = await this.client.query("SELECT confdeltype, confupdtype, conindid, conname, contype FROM pg_constraint WHERE conrelid = $1 ORDER BY conname", [table.oid]);
@@ -99,37 +163,6 @@ class PGDB extends db_1.DB {
99
163
  await this.client.query(statement);
100
164
  }
101
165
  }
102
- async end() {
103
- await this.pool.end();
104
- }
105
- fieldType(attribute) {
106
- const { size, type } = attribute;
107
- let ret;
108
- switch (type) {
109
- case "DATETIME":
110
- return ["DATETIME", "TIMESTAMP (3) WITH TIME ZONE"];
111
- case "INT":
112
- ret = size === 2 ? "SMALLINT" : "INTEGER";
113
- return [ret, ret];
114
- case "INT8":
115
- return ["BIGINT", "BIGINT"];
116
- case "VARCHAR":
117
- return ["VARCHAR", "VARCHAR" + (size ? `(${size})` : "")];
118
- }
119
- throw new Error(`Unknown type: '${type}', '${size}'`);
120
- }
121
- async syncDataBase() {
122
- let err;
123
- try {
124
- await super.syncDataBase();
125
- }
126
- catch (e) {
127
- err = e;
128
- }
129
- this.client.release();
130
- if (err)
131
- throw err;
132
- }
133
166
  async syncConstraints(table) {
134
167
  for (const constraint of table.constraints) {
135
168
  const { attribute, constraintName, type } = constraint;
@@ -154,11 +187,27 @@ class PGDB extends db_1.DB {
154
187
  }
155
188
  }
156
189
  }
190
+ fieldType(attribute) {
191
+ const { size, type } = attribute;
192
+ let ret;
193
+ switch (type) {
194
+ case "DATETIME":
195
+ return ["DATETIME", "TIMESTAMP (3) WITH TIME ZONE"];
196
+ case "INT":
197
+ ret = size === 2 ? "SMALLINT" : "INTEGER";
198
+ return [ret, ret];
199
+ case "INT8":
200
+ return ["BIGINT", "BIGINT"];
201
+ case "VARCHAR":
202
+ return ["VARCHAR", "VARCHAR" + (size ? `(${size})` : "")];
203
+ }
204
+ throw new Error(`Unknown type: '${type}', '${size}'`);
205
+ }
157
206
  async syncFields(table) {
158
- const { attributes, oid, tableName } = table;
207
+ const { attributes, autoIncrement, oid, tableName } = table;
159
208
  for (const attribute of attributes) {
160
209
  const { fieldName, notNull, size } = attribute;
161
- const defaultValue = attribute.defaultValue === undefined ? undefined : (0, pg_format_1.default)("%L", attribute.defaultValue);
210
+ const defaultValue = attribute.defaultValue === undefined ? (autoIncrement && fieldName === "id" ? `nextval('${tableName}_id_seq'::regclass)` : undefined) : this.escape(attribute.defaultValue);
162
211
  const [base, type] = this.fieldType(attribute);
163
212
  const where = "attrelid = $1 AND attnum > 0 AND atttypid = pg_type.oid AND attislocal = 't' AND attname = $2";
164
213
  const res = await this.client.query(`SELECT attnotnull, atttypmod, typname, ${(0, adsrc_1.adsrc)(this.version)} FROM pg_type, pg_attribute LEFT JOIN pg_attrdef ON adrelid = attrelid AND adnum = attnum WHERE ${where}`, [oid, fieldName]);
@@ -174,32 +223,32 @@ class PGDB extends db_1.DB {
174
223
  if (this.sync)
175
224
  await this.client.query(statement);
176
225
  };
177
- const setNotNull = async (isNull) => {
178
- if (isNull === notNull)
226
+ const setNotNull = async (isNotNull) => {
227
+ if (isNotNull === notNull)
179
228
  return;
180
229
  const statement = `ALTER TABLE ${tableName} ALTER COLUMN ${fieldName} ${notNull ? "SET" : "DROP"} NOT NULL`;
181
230
  this.syncLog(statement);
182
231
  if (this.sync)
183
232
  await this.client.query(statement);
184
233
  };
185
- const setDefault = async (isNull) => {
234
+ const setDefault = async (isNotNull, create) => {
186
235
  if (defaultValue !== undefined) {
187
236
  let statement = `ALTER TABLE ${tableName} ALTER COLUMN ${fieldName} SET DEFAULT ${defaultValue}`;
188
237
  this.syncLog(statement);
189
238
  if (this.sync)
190
239
  await this.client.query(statement);
191
- if (isNull) {
240
+ if (!isNotNull && !create) {
192
241
  statement = `UPDATE ${tableName} SET ${fieldName} = ${defaultValue} WHERE ${fieldName} IS NULL`;
193
242
  this.syncLog(statement);
194
243
  if (this.sync)
195
244
  this.client.query(statement);
196
245
  }
197
246
  }
198
- await setNotNull(isNull);
247
+ await setNotNull(isNotNull);
199
248
  };
200
249
  if (!res.rowCount) {
201
250
  await addField();
202
- await setDefault(false);
251
+ await setDefault(false, true);
203
252
  }
204
253
  else {
205
254
  const { adsrc, attnotnull, atttypmod, typname } = res.rows[0];
@@ -207,7 +256,7 @@ class PGDB extends db_1.DB {
207
256
  if (needDrop.filter(([type, name]) => attribute.type === type && typname === name).length) {
208
257
  await this.dropField(tableName, fieldName);
209
258
  await addField();
210
- await setDefault(false);
259
+ await setDefault(false, true);
211
260
  }
212
261
  else {
213
262
  if (adsrc)
@@ -217,7 +266,7 @@ class PGDB extends db_1.DB {
217
266
  this.syncLog(statement);
218
267
  if (this.sync)
219
268
  await this.client.query(statement);
220
- await setDefault(attnotnull);
269
+ await setDefault(attnotnull, false);
221
270
  }
222
271
  }
223
272
  else if (defaultValue === undefined) {
@@ -225,8 +274,8 @@ class PGDB extends db_1.DB {
225
274
  dropDefault();
226
275
  await setNotNull(attnotnull);
227
276
  }
228
- else if (!adsrc || adsrc.split("::")[0] !== defaultValue)
229
- await setDefault(attnotnull);
277
+ else if (!adsrc || this.defaultNeq(adsrc, defaultValue))
278
+ await setDefault(attnotnull, false);
230
279
  }
231
280
  }
232
281
  }
@@ -309,4 +358,9 @@ class PGDB extends db_1.DB {
309
358
  }
310
359
  }
311
360
  exports.PGDB = PGDB;
312
- // farray[0].defaultValue = "nextval('" + tname + "_id_seq'::regclass)";
361
+ class TransactionPG extends db_1.Transaction {
362
+ constructor() {
363
+ super(...arguments);
364
+ this.client = {};
365
+ }
366
+ }
package/lib/adsrc.ts DELETED
@@ -1,3 +0,0 @@
1
- export function adsrc(version: number) {
2
- return version >= 12 ? "pg_get_expr(pg_attrdef.adbin, pg_attrdef.adrelid) AS adsrc" : "adsrc";
3
- }
package/lib/pgdb.ts DELETED
@@ -1,359 +0,0 @@
1
- import { DatabaseError, Pool, PoolClient, PoolConfig } from "pg";
2
- import format from "pg-format";
3
- import { Attribute, DB, ForeignKeyActions, Index, Natural, Table } from "sedentary/lib/db";
4
- import { adsrc } from "./adsrc";
5
-
6
- const needDrop = [
7
- ["DATETIME", "int2"],
8
- ["DATETIME", "int4"],
9
- ["DATETIME", "int8"],
10
- ["INT", "timestamptz"],
11
- ["INT8", "timestamptz"]
12
- ];
13
- const needUsing = [
14
- ["DATETIME", "varchar"],
15
- ["INT", "varchar"],
16
- ["INT8", "varchar"]
17
- ];
18
- const types = { int2: "SMALLINT", int4: "INTEGER", int8: "BIGINT", varchar: "VARCHAR" };
19
-
20
- const actions: { [k in ForeignKeyActions]: string } = { cascade: "c", "no action": "a", restrict: "r", "set default": "d", "set null": "n" };
21
-
22
- export class PGDB extends DB {
23
- private client: PoolClient;
24
- private indexes: string[];
25
- private pool: Pool;
26
- private version: number;
27
-
28
- constructor(connection: PoolConfig, log: (message: string) => void) {
29
- super(log);
30
-
31
- this.client = {} as PoolClient;
32
- this.indexes = [];
33
- this.pool = new Pool(connection);
34
- this.version = 0;
35
- }
36
-
37
- async connect(): Promise<void> {
38
- this.client = await this.pool.connect();
39
-
40
- const res = await this.client.query("SELECT version()");
41
-
42
- this.version = parseInt(res.rows[0].version.split(" ")[1].split(".")[0], 10);
43
- }
44
-
45
- async dropConstraints(table: Table): Promise<number[]> {
46
- const indexes: number[] = [];
47
- const res = await this.client.query("SELECT confdeltype, confupdtype, conindid, conname, contype FROM pg_constraint WHERE conrelid = $1 ORDER BY conname", [table.oid]);
48
-
49
- for(const row of res.rows) {
50
- const arr = table.constraints.filter(_ => _.constraintName === row.conname && _.type === row.contype);
51
- let drop = false;
52
-
53
- if(arr.length === 0) drop = true;
54
- else if(row.contype === "u") indexes.push(row.conindid);
55
- else {
56
- const { options } = arr[0].attribute.foreignKey as { attributeName: string; fieldName: string; options: { onDelete: ForeignKeyActions; onUpdate: ForeignKeyActions }; tableName: string };
57
-
58
- if(actions[options.onDelete] !== row.confdeltype || actions[options.onUpdate] !== row.confupdtype) drop = true;
59
- }
60
-
61
- if(drop) {
62
- const statement = `ALTER TABLE ${table.tableName} DROP CONSTRAINT ${row.conname} CASCADE`;
63
-
64
- this.syncLog(statement);
65
- if(this.sync) await this.client.query(statement);
66
- }
67
- }
68
-
69
- return indexes;
70
- }
71
-
72
- async dropField(tableName: string, fieldName: string): Promise<void> {
73
- const statement = `ALTER TABLE ${tableName} DROP COLUMN ${fieldName}`;
74
-
75
- this.syncLog(statement);
76
- if(this.sync) await this.client.query(statement);
77
- }
78
-
79
- async dropFields(table: Table): Promise<void> {
80
- 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]);
81
-
82
- for(const i in res.rows) if(! table.findField(res.rows[i].attname)) await this.dropField(table.tableName, res.rows[i].attname);
83
- }
84
-
85
- async dropIndexes(table: Table, constraintIndexes: number[]): Promise<void> {
86
- const { indexes, oid } = table;
87
- const iobject: { [key: string]: Index } = {};
88
- const res = await this.client.query(
89
- "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",
90
- [oid]
91
- );
92
-
93
- for(const row of res.rows) {
94
- const { amname, attname, indexrelid, indisunique, relname } = row;
95
-
96
- if(! constraintIndexes.includes(indexrelid)) {
97
- if(iobject[relname]) iobject[relname].fields.push(attname);
98
- else iobject[relname] = { fields: [attname], indexName: relname, type: amname, unique: indisunique };
99
- }
100
- }
101
-
102
- this.indexes = [];
103
- for(const index of indexes) {
104
- const { indexName } = index;
105
-
106
- if(iobject[indexName] && this.indexesEq(index, iobject[indexName])) {
107
- this.indexes.push(indexName);
108
- delete iobject[indexName];
109
- }
110
- }
111
-
112
- for(const index of Object.keys(iobject).sort()) {
113
- const statement = `DROP INDEX ${index}`;
114
-
115
- this.syncLog(statement);
116
- if(this.sync) await this.client.query(statement);
117
- }
118
- }
119
-
120
- async end(): Promise<void> {
121
- await this.pool.end();
122
- }
123
-
124
- fieldType(attribute: Attribute<Natural, unknown>): string[] {
125
- const { size, type } = attribute;
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})` : "")];
139
- }
140
-
141
- throw new Error(`Unknown type: '${type}', '${size}'`);
142
- }
143
-
144
- async syncDataBase(): Promise<void> {
145
- let err: unknown;
146
-
147
- try {
148
- await super.syncDataBase();
149
- } catch(e) {
150
- err = e;
151
- }
152
-
153
- this.client.release();
154
-
155
- if(err) throw err;
156
- }
157
-
158
- async syncConstraints(table: Table): Promise<void> {
159
- for(const constraint of table.constraints) {
160
- const { attribute, constraintName, type } = constraint;
161
- 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", [
162
- table.oid,
163
- attribute.fieldName
164
- ]);
165
-
166
- if(! res.rowCount) {
167
- let query: string;
168
-
169
- if(type === "f") {
170
- const { fieldName, options, tableName } = attribute.foreignKey as {
171
- attributeName: string;
172
- fieldName: string;
173
- options: { onDelete: ForeignKeyActions; onUpdate: ForeignKeyActions };
174
- tableName: string;
175
- };
176
- const onDelete = options.onDelete !== "no action" ? ` ON DELETE ${options.onDelete.toUpperCase()}` : "";
177
- const onUpdate = options.onUpdate !== "no action" ? ` ON UPDATE ${options.onUpdate.toUpperCase()}` : "";
178
-
179
- query = `FOREIGN KEY (${attribute.fieldName}) REFERENCES ${tableName}(${fieldName})${onDelete}${onUpdate}`;
180
- } else query = `UNIQUE(${attribute.fieldName})`;
181
-
182
- const statement = `ALTER TABLE ${table.tableName} ADD CONSTRAINT ${constraintName} ${query}`;
183
-
184
- this.syncLog(statement);
185
- if(this.sync) await this.client.query(statement);
186
- }
187
- }
188
- }
189
-
190
- async syncFields(table: Table): Promise<void> {
191
- const { attributes, oid, tableName } = table;
192
-
193
- for(const attribute of attributes) {
194
- const { fieldName, notNull, size } = attribute;
195
- const defaultValue = attribute.defaultValue === undefined ? undefined : format("%L", attribute.defaultValue);
196
- const [base, type] = this.fieldType(attribute);
197
- const where = "attrelid = $1 AND attnum > 0 AND atttypid = pg_type.oid AND attislocal = 't' AND attname = $2";
198
-
199
- const res = await this.client.query(
200
- `SELECT attnotnull, atttypmod, typname, ${adsrc(this.version)} FROM pg_type, pg_attribute LEFT JOIN pg_attrdef ON adrelid = attrelid AND adnum = attnum WHERE ${where}`,
201
- [oid, fieldName]
202
- );
203
-
204
- const addField = async () => {
205
- const statement = `ALTER TABLE ${tableName} ADD COLUMN ${fieldName} ${type}`;
206
-
207
- this.syncLog(statement);
208
- if(this.sync) await this.client.query(statement);
209
- };
210
-
211
- const dropDefault = async () => {
212
- const statement = `ALTER TABLE ${tableName} ALTER COLUMN ${fieldName} DROP DEFAULT`;
213
-
214
- this.syncLog(statement);
215
- if(this.sync) await this.client.query(statement);
216
- };
217
-
218
- const setNotNull = async (isNull: boolean) => {
219
- if(isNull === notNull) return;
220
-
221
- const statement = `ALTER TABLE ${tableName} ALTER COLUMN ${fieldName} ${notNull ? "SET" : "DROP"} NOT NULL`;
222
-
223
- this.syncLog(statement);
224
- if(this.sync) await this.client.query(statement);
225
- };
226
-
227
- const setDefault = async (isNull: boolean) => {
228
- if(defaultValue !== undefined) {
229
- let statement = `ALTER TABLE ${tableName} ALTER COLUMN ${fieldName} SET DEFAULT ${defaultValue}`;
230
-
231
- this.syncLog(statement);
232
- if(this.sync) await this.client.query(statement);
233
-
234
- if(isNull) {
235
- statement = `UPDATE ${tableName} SET ${fieldName} = ${defaultValue} WHERE ${fieldName} IS NULL`;
236
-
237
- this.syncLog(statement);
238
- if(this.sync) this.client.query(statement);
239
- }
240
- }
241
-
242
- await setNotNull(isNull);
243
- };
244
-
245
- if(! res.rowCount) {
246
- await addField();
247
- await setDefault(false);
248
- } else {
249
- const { adsrc, attnotnull, atttypmod, typname } = res.rows[0];
250
-
251
- if(types[typname as keyof typeof types] !== base || (base === "VARCHAR" && (size ? size + 4 !== atttypmod : atttypmod !== -1))) {
252
- if(needDrop.filter(([type, name]) => attribute.type === type && typname === name).length) {
253
- await this.dropField(tableName, fieldName);
254
- await addField();
255
- await setDefault(false);
256
- } else {
257
- if(adsrc) dropDefault();
258
-
259
- const using = needUsing.filter(([type, name]) => attribute.type === type && typname === name).length ? " USING " + fieldName + "::" + type : "";
260
- const statement = `ALTER TABLE ${tableName} ALTER COLUMN ${fieldName} TYPE ${type}${using}`;
261
-
262
- this.syncLog(statement);
263
- if(this.sync) await this.client.query(statement);
264
- await setDefault(attnotnull);
265
- }
266
- } else if(defaultValue === undefined) {
267
- if(adsrc) dropDefault();
268
- await setNotNull(attnotnull);
269
- } else if(! adsrc || adsrc.split("::")[0] !== defaultValue) await setDefault(attnotnull);
270
- }
271
- }
272
- }
273
-
274
- async syncIndexes(table: Table): Promise<void> {
275
- const { indexes, tableName } = table;
276
-
277
- for(const index of indexes) {
278
- const { fields, indexName, type, unique } = index;
279
-
280
- if(! this.indexes.includes(indexName)) {
281
- const statement = `CREATE${unique ? " UNIQUE" : ""} INDEX ${indexName} ON ${tableName} USING ${type} (${fields.join(", ")})`;
282
-
283
- this.syncLog(statement);
284
- if(this.sync) await this.client.query(statement);
285
- }
286
- }
287
- }
288
-
289
- async syncSequence(table: Table): Promise<void> {
290
- if(! table.autoIncrementOwn) return;
291
-
292
- const statement = `ALTER SEQUENCE ${table.tableName}_id_seq OWNED BY ${table.tableName}.id`;
293
-
294
- this.syncLog(statement);
295
- if(this.sync) await this.client.query(statement);
296
- }
297
-
298
- async syncTable(table: Table): Promise<void> {
299
- if(table.autoIncrement) {
300
- await (async () => {
301
- try {
302
- await this.client.query(`SELECT currval('${table.tableName}_id_seq')`);
303
- } catch(e) {
304
- if(e instanceof DatabaseError && e.code === "55000") return;
305
- if(e instanceof DatabaseError && e.code === "42P01") {
306
- const statement = `CREATE SEQUENCE ${table.tableName}_id_seq`;
307
-
308
- this.syncLog(statement);
309
- if(this.sync) await this.client.query(statement);
310
- table.autoIncrementOwn = true;
311
-
312
- return;
313
- }
314
-
315
- throw e;
316
- }
317
- })();
318
- }
319
-
320
- let create = false;
321
- const resTable = await this.client.query("SELECT oid FROM pg_class WHERE relname = $1", [table.tableName]);
322
-
323
- if(resTable.rowCount) {
324
- table.oid = resTable.rows[0].oid;
325
-
326
- let drop = false;
327
- const resParent = await this.client.query("SELECT inhparent FROM pg_inherits WHERE inhrelid = $1", [table.oid]);
328
-
329
- if(resParent.rowCount) {
330
- if(! table.parent) drop = true;
331
- else if(this.findTable(table.parent.tableName).oid === resParent.rows[0].inhparent) return;
332
-
333
- drop = true;
334
- } else if(table.parent) drop = true;
335
-
336
- if(drop) {
337
- const statement = `DROP TABLE ${table.tableName} CASCADE`;
338
-
339
- create = true;
340
- this.syncLog(statement);
341
- if(this.sync) await this.client.query(statement);
342
- }
343
- } else create = true;
344
-
345
- if(create) {
346
- const parent = table.parent ? ` INHERITS (${table.parent.tableName})` : "";
347
- const statement = `CREATE TABLE ${table.tableName} ()${parent}`;
348
-
349
- this.syncLog(statement);
350
- if(this.sync) await this.client.query(statement);
351
-
352
- const resTable = await this.client.query("SELECT oid FROM pg_class WHERE relname = $1", [table.tableName]);
353
-
354
- table.oid = resTable.rows[0]?.oid;
355
- }
356
- }
357
- }
358
-
359
- // farray[0].defaultValue = "nextval('" + tname + "_id_seq'::regclass)";