sedentary-pg 0.0.17 → 0.0.22
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 +28 -0
- package/index.d.ts +4 -4
- package/index.js +5 -6
- package/lib/pgdb.js +28 -16
- package/lib/pgdb.ts +38 -20
- package/package.json +32 -10
package/README.md
CHANGED
|
@@ -33,6 +33,34 @@
|
|
|
33
33
|
|
|
34
34
|
The **PostgreSQL** specilized package of [Sedentary](https://www.npmjs.com/package/sedentary).
|
|
35
35
|
|
|
36
|
+
# Usage
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
import { SedentaryPG } from "sedentary-pg";
|
|
40
|
+
|
|
41
|
+
const db = new SedentaryPG(/* PG connection */);
|
|
42
|
+
|
|
43
|
+
class Items extends db.model("Item", {
|
|
44
|
+
num: db.INT,
|
|
45
|
+
str: db.VARCHAR(30)
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
(async function () {
|
|
49
|
+
await db.connect();
|
|
50
|
+
|
|
51
|
+
const item = Items.create();
|
|
52
|
+
|
|
53
|
+
item.num = 0;
|
|
54
|
+
item.str = "0";
|
|
55
|
+
|
|
56
|
+
await item.save();
|
|
57
|
+
|
|
58
|
+
const records = await Items.load({});
|
|
59
|
+
|
|
60
|
+
console.log(records); // [{ id: 1, num: 0, str: "0" }]
|
|
61
|
+
})();
|
|
62
|
+
```
|
|
63
|
+
|
|
36
64
|
# Installation
|
|
37
65
|
|
|
38
66
|
With [npm](https://www.npmjs.com/package/sedentary-pg):
|
package/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { EntryBase, ForeignKeyOptions, Natural, Sedentary, SedentaryOptions, Type } from "sedentary";
|
|
2
|
+
import { Attribute } from "sedentary/lib/db";
|
|
2
3
|
import { PoolConfig } from "pg";
|
|
3
|
-
export {
|
|
4
|
-
export { ModelOptions, Natural, SedentaryOptions, Type, TypeDefinition } from "sedentary";
|
|
4
|
+
export { EntryBase, SedentaryOptions, Type } from "sedentary";
|
|
5
5
|
export declare class SedentaryPG extends Sedentary {
|
|
6
6
|
constructor(connection: PoolConfig, options?: SedentaryOptions);
|
|
7
|
-
FKEY<N extends Natural, E extends
|
|
7
|
+
FKEY<N extends Natural, E extends EntryBase>(attribute: Attribute<N, E>, options?: ForeignKeyOptions): Type<N, E>;
|
|
8
8
|
}
|
|
9
9
|
export declare const Package: typeof SedentaryPG;
|
package/index.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Package = exports.SedentaryPG = exports.Type = exports.
|
|
3
|
+
exports.Package = exports.SedentaryPG = exports.Type = exports.EntryBase = void 0;
|
|
4
4
|
const sedentary_1 = require("sedentary");
|
|
5
5
|
const pgdb_1 = require("./lib/pgdb");
|
|
6
6
|
var sedentary_2 = require("sedentary");
|
|
7
|
-
Object.defineProperty(exports, "
|
|
8
|
-
|
|
9
|
-
Object.defineProperty(exports, "Type", { enumerable: true, get: function () { return sedentary_3.Type; } });
|
|
7
|
+
Object.defineProperty(exports, "EntryBase", { enumerable: true, get: function () { return sedentary_2.EntryBase; } });
|
|
8
|
+
Object.defineProperty(exports, "Type", { enumerable: true, get: function () { return sedentary_2.Type; } });
|
|
10
9
|
class SedentaryPG extends sedentary_1.Sedentary {
|
|
11
10
|
constructor(connection, options) {
|
|
12
11
|
super("", options);
|
|
@@ -14,11 +13,11 @@ class SedentaryPG extends sedentary_1.Sedentary {
|
|
|
14
13
|
throw new Error("SedentaryPG.constructor: 'connection' argument: Wrong type, expected 'Object'");
|
|
15
14
|
this.db = new pgdb_1.PGDB(connection, this.log);
|
|
16
15
|
}
|
|
17
|
-
FKEY(attribute) {
|
|
16
|
+
FKEY(attribute, options) {
|
|
18
17
|
const { attributeName, modelName, unique } = attribute;
|
|
19
18
|
if (!unique)
|
|
20
19
|
throw new Error(`Sedentary.FKEY: '${modelName}' model: '${attributeName}' attribute: is not unique: can't be used as FKEY target`);
|
|
21
|
-
return super.FKEY(attribute);
|
|
20
|
+
return super.FKEY(attribute, options);
|
|
22
21
|
}
|
|
23
22
|
}
|
|
24
23
|
exports.SedentaryPG = SedentaryPG;
|
package/lib/pgdb.js
CHANGED
|
@@ -21,10 +21,14 @@ const needUsing = [
|
|
|
21
21
|
["INT8", "varchar"]
|
|
22
22
|
];
|
|
23
23
|
const types = { int2: "SMALLINT", int4: "INTEGER", int8: "BIGINT", varchar: "VARCHAR" };
|
|
24
|
+
const actions = { cascade: "c", "no action": "a", restrict: "r", "set default": "d", "set null": "n" };
|
|
24
25
|
class PGDB extends db_1.DB {
|
|
25
26
|
constructor(connection, log) {
|
|
26
27
|
super(log);
|
|
28
|
+
this.client = {};
|
|
29
|
+
this.indexes = [];
|
|
27
30
|
this.pool = new pg_1.Pool(connection);
|
|
31
|
+
this.version = 0;
|
|
28
32
|
}
|
|
29
33
|
async connect() {
|
|
30
34
|
this.client = await this.pool.connect();
|
|
@@ -33,17 +37,25 @@ class PGDB extends db_1.DB {
|
|
|
33
37
|
}
|
|
34
38
|
async dropConstraints(table) {
|
|
35
39
|
const indexes = [];
|
|
36
|
-
const res = await this.client.query("SELECT
|
|
40
|
+
const res = await this.client.query("SELECT confdeltype, confupdtype, conindid, conname, contype FROM pg_constraint WHERE conrelid = $1 ORDER BY conname", [table.oid]);
|
|
37
41
|
for (const row of res.rows) {
|
|
38
|
-
const
|
|
39
|
-
|
|
42
|
+
const arr = table.constraints.filter(_ => _.constraintName === row.conname && _.type === row.contype);
|
|
43
|
+
let drop = false;
|
|
44
|
+
if (arr.length === 0)
|
|
45
|
+
drop = true;
|
|
46
|
+
else if (row.contype === "u")
|
|
47
|
+
indexes.push(row.conindid);
|
|
48
|
+
else {
|
|
49
|
+
const { options } = arr[0].attribute.foreignKey;
|
|
50
|
+
if (actions[options.onDelete] !== row.confdeltype || actions[options.onUpdate] !== row.confupdtype)
|
|
51
|
+
drop = true;
|
|
52
|
+
}
|
|
53
|
+
if (drop) {
|
|
40
54
|
const statement = `ALTER TABLE ${table.tableName} DROP CONSTRAINT ${row.conname} CASCADE`;
|
|
41
55
|
this.syncLog(statement);
|
|
42
56
|
if (this.sync)
|
|
43
57
|
await this.client.query(statement);
|
|
44
58
|
}
|
|
45
|
-
else
|
|
46
|
-
indexes.push(row.conindid);
|
|
47
59
|
}
|
|
48
60
|
return indexes;
|
|
49
61
|
}
|
|
@@ -127,14 +139,14 @@ class PGDB extends db_1.DB {
|
|
|
127
139
|
]);
|
|
128
140
|
if (!res.rowCount) {
|
|
129
141
|
let query;
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
query = `UNIQUE(${attribute.fieldName})`;
|
|
136
|
-
break;
|
|
142
|
+
if (type === "f") {
|
|
143
|
+
const { fieldName, options, tableName } = attribute.foreignKey;
|
|
144
|
+
const onDelete = options.onDelete !== "no action" ? ` ON DELETE ${options.onDelete.toUpperCase()}` : "";
|
|
145
|
+
const onUpdate = options.onUpdate !== "no action" ? ` ON UPDATE ${options.onUpdate.toUpperCase()}` : "";
|
|
146
|
+
query = `FOREIGN KEY (${attribute.fieldName}) REFERENCES ${tableName}(${fieldName})${onDelete}${onUpdate}`;
|
|
137
147
|
}
|
|
148
|
+
else
|
|
149
|
+
query = `UNIQUE(${attribute.fieldName})`;
|
|
138
150
|
const statement = `ALTER TABLE ${table.tableName} ADD CONSTRAINT ${constraintName} ${query}`;
|
|
139
151
|
this.syncLog(statement);
|
|
140
152
|
if (this.sync)
|
|
@@ -246,9 +258,9 @@ class PGDB extends db_1.DB {
|
|
|
246
258
|
await this.client.query(`SELECT currval('${table.tableName}_id_seq')`);
|
|
247
259
|
}
|
|
248
260
|
catch (e) {
|
|
249
|
-
if (e.code === "55000")
|
|
261
|
+
if (e instanceof pg_1.DatabaseError && e.code === "55000")
|
|
250
262
|
return;
|
|
251
|
-
if (e.code === "42P01") {
|
|
263
|
+
if (e instanceof pg_1.DatabaseError && e.code === "42P01") {
|
|
252
264
|
const statement = `CREATE SEQUENCE ${table.tableName}_id_seq`;
|
|
253
265
|
this.syncLog(statement);
|
|
254
266
|
if (this.sync)
|
|
@@ -260,11 +272,11 @@ class PGDB extends db_1.DB {
|
|
|
260
272
|
}
|
|
261
273
|
})();
|
|
262
274
|
}
|
|
263
|
-
let create;
|
|
275
|
+
let create = false;
|
|
264
276
|
const resTable = await this.client.query("SELECT oid FROM pg_class WHERE relname = $1", [table.tableName]);
|
|
265
277
|
if (resTable.rowCount) {
|
|
266
278
|
table.oid = resTable.rows[0].oid;
|
|
267
|
-
let drop;
|
|
279
|
+
let drop = false;
|
|
268
280
|
const resParent = await this.client.query("SELECT inhparent FROM pg_inherits WHERE inhrelid = $1", [table.oid]);
|
|
269
281
|
if (resParent.rowCount) {
|
|
270
282
|
if (!table.parent)
|
package/lib/pgdb.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Pool, PoolClient, PoolConfig } from "pg";
|
|
1
|
+
import { DatabaseError, Pool, PoolClient, PoolConfig } from "pg";
|
|
2
2
|
import format from "pg-format";
|
|
3
|
-
import { Attribute, DB, Index, Natural, Table } from "sedentary/lib/db";
|
|
3
|
+
import { Attribute, DB, ForeignKeyActions, Index, Natural, Table } from "sedentary/lib/db";
|
|
4
4
|
import { adsrc } from "./adsrc";
|
|
5
5
|
|
|
6
6
|
const needDrop = [
|
|
@@ -17,6 +17,8 @@ const needUsing = [
|
|
|
17
17
|
];
|
|
18
18
|
const types = { int2: "SMALLINT", int4: "INTEGER", int8: "BIGINT", varchar: "VARCHAR" };
|
|
19
19
|
|
|
20
|
+
const actions: { [k in ForeignKeyActions]: string } = { cascade: "c", "no action": "a", restrict: "r", "set default": "d", "set null": "n" };
|
|
21
|
+
|
|
20
22
|
export class PGDB extends DB {
|
|
21
23
|
private client: PoolClient;
|
|
22
24
|
private indexes: string[];
|
|
@@ -26,7 +28,10 @@ export class PGDB extends DB {
|
|
|
26
28
|
constructor(connection: PoolConfig, log: (message: string) => void) {
|
|
27
29
|
super(log);
|
|
28
30
|
|
|
31
|
+
this.client = {} as PoolClient;
|
|
32
|
+
this.indexes = [];
|
|
29
33
|
this.pool = new Pool(connection);
|
|
34
|
+
this.version = 0;
|
|
30
35
|
}
|
|
31
36
|
|
|
32
37
|
async connect(): Promise<void> {
|
|
@@ -39,17 +44,26 @@ export class PGDB extends DB {
|
|
|
39
44
|
|
|
40
45
|
async dropConstraints(table: Table): Promise<number[]> {
|
|
41
46
|
const indexes: number[] = [];
|
|
42
|
-
const res = await this.client.query("SELECT
|
|
47
|
+
const res = await this.client.query("SELECT confdeltype, confupdtype, conindid, conname, contype FROM pg_constraint WHERE conrelid = $1 ORDER BY conname", [table.oid]);
|
|
43
48
|
|
|
44
49
|
for(const row of res.rows) {
|
|
45
|
-
const
|
|
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
|
+
}
|
|
46
60
|
|
|
47
|
-
if(
|
|
61
|
+
if(drop) {
|
|
48
62
|
const statement = `ALTER TABLE ${table.tableName} DROP CONSTRAINT ${row.conname} CASCADE`;
|
|
49
63
|
|
|
50
64
|
this.syncLog(statement);
|
|
51
65
|
if(this.sync) await this.client.query(statement);
|
|
52
|
-
}
|
|
66
|
+
}
|
|
53
67
|
}
|
|
54
68
|
|
|
55
69
|
return indexes;
|
|
@@ -128,7 +142,7 @@ export class PGDB extends DB {
|
|
|
128
142
|
}
|
|
129
143
|
|
|
130
144
|
async syncDataBase(): Promise<void> {
|
|
131
|
-
let err:
|
|
145
|
+
let err: unknown;
|
|
132
146
|
|
|
133
147
|
try {
|
|
134
148
|
await super.syncDataBase();
|
|
@@ -152,14 +166,18 @@ export class PGDB extends DB {
|
|
|
152
166
|
if(! res.rowCount) {
|
|
153
167
|
let query: string;
|
|
154
168
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
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})`;
|
|
163
181
|
|
|
164
182
|
const statement = `ALTER TABLE ${table.tableName} ADD CONSTRAINT ${constraintName} ${query}`;
|
|
165
183
|
|
|
@@ -230,7 +248,7 @@ export class PGDB extends DB {
|
|
|
230
248
|
} else {
|
|
231
249
|
const { adsrc, attnotnull, atttypmod, typname } = res.rows[0];
|
|
232
250
|
|
|
233
|
-
if(types[typname] !== base || (base === "VARCHAR" && (size ? size + 4 !== atttypmod : atttypmod !== -1))) {
|
|
251
|
+
if(types[typname as keyof typeof types] !== base || (base === "VARCHAR" && (size ? size + 4 !== atttypmod : atttypmod !== -1))) {
|
|
234
252
|
if(needDrop.filter(([type, name]) => attribute.type === type && typname === name).length) {
|
|
235
253
|
await this.dropField(tableName, fieldName);
|
|
236
254
|
await addField();
|
|
@@ -283,8 +301,8 @@ export class PGDB extends DB {
|
|
|
283
301
|
try {
|
|
284
302
|
await this.client.query(`SELECT currval('${table.tableName}_id_seq')`);
|
|
285
303
|
} catch(e) {
|
|
286
|
-
if(e.code === "55000") return;
|
|
287
|
-
if(e.code === "42P01") {
|
|
304
|
+
if(e instanceof DatabaseError && e.code === "55000") return;
|
|
305
|
+
if(e instanceof DatabaseError && e.code === "42P01") {
|
|
288
306
|
const statement = `CREATE SEQUENCE ${table.tableName}_id_seq`;
|
|
289
307
|
|
|
290
308
|
this.syncLog(statement);
|
|
@@ -299,13 +317,13 @@ export class PGDB extends DB {
|
|
|
299
317
|
})();
|
|
300
318
|
}
|
|
301
319
|
|
|
302
|
-
let create
|
|
320
|
+
let create = false;
|
|
303
321
|
const resTable = await this.client.query("SELECT oid FROM pg_class WHERE relname = $1", [table.tableName]);
|
|
304
322
|
|
|
305
323
|
if(resTable.rowCount) {
|
|
306
324
|
table.oid = resTable.rows[0].oid;
|
|
307
325
|
|
|
308
|
-
let drop
|
|
326
|
+
let drop = false;
|
|
309
327
|
const resParent = await this.client.query("SELECT inhparent FROM pg_inherits WHERE inhrelid = $1", [table.oid]);
|
|
310
328
|
|
|
311
329
|
if(resParent.rowCount) {
|
package/package.json
CHANGED
|
@@ -1,26 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"author": "Daniele Ricci <daniele.icc@gmail.com> (https://github.com/iccicci)",
|
|
3
3
|
"bugs": "https://github.com/iccicci/sedentary-pg/issues",
|
|
4
|
+
"contributors": [
|
|
5
|
+
"Daniele Ricci <daniele.icc@gmail.com> (https://github.com/iccicci)",
|
|
6
|
+
"yossarian <sergiybiluk@gmail.com> (https://github.com/captain-yossarian)"
|
|
7
|
+
],
|
|
4
8
|
"dependencies": {
|
|
5
|
-
"@types/pg": "8.6.1",
|
|
6
|
-
"@types/pg-format": "1.0.2",
|
|
7
9
|
"pg": "8.7.1",
|
|
8
10
|
"pg-format": "1.0.4",
|
|
9
|
-
"sedentary": "0.0.
|
|
11
|
+
"sedentary": "0.0.22"
|
|
10
12
|
},
|
|
11
13
|
"description": "The ORM which never needs to migrate - PostgreSQL",
|
|
12
14
|
"devDependencies": {
|
|
13
15
|
"@types/mocha": "9.0.0",
|
|
14
|
-
"@types/node": "
|
|
16
|
+
"@types/node": "17.0.5",
|
|
17
|
+
"@types/pg": "8.6.3",
|
|
18
|
+
"@types/pg-format": "1.0.2",
|
|
15
19
|
"@types/yamljs": "0.2.31",
|
|
16
|
-
"@typescript-eslint/eslint-plugin": "5.
|
|
17
|
-
"@typescript-eslint/parser": "5.
|
|
18
|
-
"eslint": "8.
|
|
20
|
+
"@typescript-eslint/eslint-plugin": "5.8.1",
|
|
21
|
+
"@typescript-eslint/parser": "5.8.1",
|
|
22
|
+
"eslint": "8.5.0",
|
|
19
23
|
"mocha": "9.1.3",
|
|
20
24
|
"nyc": "15.1.0",
|
|
21
|
-
"prettier": "2.5.
|
|
25
|
+
"prettier": "2.5.1",
|
|
22
26
|
"ts-node": "10.4.0",
|
|
23
|
-
"
|
|
27
|
+
"tsd": "0.19.0",
|
|
28
|
+
"typescript": "4.5.4",
|
|
24
29
|
"yamljs": "0.3.0"
|
|
25
30
|
},
|
|
26
31
|
"engines": {
|
|
@@ -61,6 +66,23 @@
|
|
|
61
66
|
"tsc": "tsc --declaration",
|
|
62
67
|
"version": "node -r ts-node/register utils.ts version"
|
|
63
68
|
},
|
|
69
|
+
"tsd": {
|
|
70
|
+
"compilerOptions": {
|
|
71
|
+
"alwaysStrict": true,
|
|
72
|
+
"declaration": true,
|
|
73
|
+
"esModuleInterop": true,
|
|
74
|
+
"module": "commonjs",
|
|
75
|
+
"noImplicitAny": true,
|
|
76
|
+
"noImplicitReturns": true,
|
|
77
|
+
"noImplicitThis": true,
|
|
78
|
+
"strict": true,
|
|
79
|
+
"strictBindCallApply": true,
|
|
80
|
+
"strictFunctionTypes": true,
|
|
81
|
+
"strictNullChecks": true,
|
|
82
|
+
"strictPropertyInitialization": true,
|
|
83
|
+
"target": "es2017"
|
|
84
|
+
}
|
|
85
|
+
},
|
|
64
86
|
"types": "index.d.ts",
|
|
65
|
-
"version": "0.0.
|
|
87
|
+
"version": "0.0.22"
|
|
66
88
|
}
|