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 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 { Entry, Natural, SedentaryOptions, Sedentary, Type } from "sedentary";
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 { AttributeDefinition, AttributeOptions, AttributesDefinition, Entry, IndexAttributes, IndexDefinition, IndexOptions, IndexesDefinition } from "sedentary";
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 Entry>(attribute: Type<N, E>): Type<N, E>;
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.Entry = void 0;
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, "Entry", { enumerable: true, get: function () { return sedentary_2.Entry; } });
8
- var sedentary_3 = require("sedentary");
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 * FROM pg_constraint WHERE conrelid = $1 ORDER BY conname", [table.oid]);
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 constraint = table.constraints.filter(_ => _.constraintName === row.conname);
39
- if (constraint.length === 0) {
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
- switch (type) {
131
- case "f":
132
- query = `FOREIGN KEY (${attribute.fieldName}) REFERENCES ${attribute.foreignKey.tableName}(${attribute.foreignKey.fieldName})`;
133
- break;
134
- case "u":
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 * FROM pg_constraint WHERE conrelid = $1 ORDER BY conname", [table.oid]);
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 constraint = table.constraints.filter(_ => _.constraintName === row.conname);
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(constraint.length === 0) {
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
- } else indexes.push(row.conindid);
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: Error;
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
- switch(type) {
156
- case "f":
157
- query = `FOREIGN KEY (${attribute.fieldName}) REFERENCES ${attribute.foreignKey.tableName}(${attribute.foreignKey.fieldName})`;
158
- break;
159
- case "u":
160
- query = `UNIQUE(${attribute.fieldName})`;
161
- break;
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: boolean;
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: boolean;
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.17"
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.11.10",
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.4.0",
17
- "@typescript-eslint/parser": "5.4.0",
18
- "eslint": "8.3.0",
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.0",
25
+ "prettier": "2.5.1",
22
26
  "ts-node": "10.4.0",
23
- "typescript": "4.5.2",
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.17"
87
+ "version": "0.0.22"
66
88
  }