doix-db 0.0.36 → 0.0.41

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/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  module.exports = {
2
+
2
3
  DbEventLogger : require ('./lib/DbEventLogger.js'),
3
4
  DbClient: require ('./lib/DbClient.js'),
4
5
  DbPool: require ('./lib/DbPool.js'),
@@ -12,9 +13,18 @@ module.exports = {
12
13
  DbObjectMap: require ('./lib/model/DbObjectMap.js'),
13
14
  DbObject: require ('./lib/model/DbObject.js'),
14
15
  DbModel: require ('./lib/model/DbModel.js'),
16
+
17
+ DbType: require ('./lib/model/types/DbType.js'),
18
+ DbTypeArithmetic: require ('./lib/model/types/DbTypeArithmetic.js'),
19
+ DbTypeArithmeticFixed: require ('./lib/model/types/DbTypeArithmeticFixed.js'),
20
+ DbTypeArithmeticFloat: require ('./lib/model/types/DbTypeArithmeticFloat.js'),
21
+ DbTypeArithmeticInt: require ('./lib/model/types/DbTypeArithmeticInt.js'),
22
+ DbTypeCharacter: require ('./lib/model/types/DbTypeCharacter.js'),
23
+
15
24
  DbMigrationPlan:require ('./lib/migration/DbMigrationPlan.js'),
16
25
  DbQuery: require ('./lib/query/DbQuery.js'),
17
26
  DbQueryTable: require ('./lib/query/DbQueryTable.js'),
18
27
  DbQueryColumn: require ('./lib/query/DbQueryColumn.js'),
19
28
  DbQueryOr: require ('./lib/query/DbQueryOr.js'),
29
+
20
30
  }
package/lib/DbLang.js CHANGED
@@ -3,6 +3,13 @@ const stringEscape = require ('string-escape-map')
3
3
  const DbTable = require ('./model/DbTable.js')
4
4
  const DbView = require ('./model/DbView.js')
5
5
 
6
+ const DbType = require ('./model/types/DbType.js')
7
+ const DbTypeArithmetic = require ('./model/types/DbTypeArithmetic.js')
8
+ const DbTypeArithmeticFixed = require ('./model/types/DbTypeArithmeticFixed.js')
9
+ const DbTypeArithmeticFloat = require ('./model/types/DbTypeArithmeticFloat.js')
10
+ const DbTypeArithmeticInt = require ('./model/types/DbTypeArithmeticInt.js')
11
+ const DbTypeCharacter = require ('./model/types/DbTypeCharacter.js')
12
+
6
13
  const CH_Q = "'", CH_QQ = '"'
7
14
 
8
15
  const Q_ESC = new stringEscape ([
@@ -17,6 +24,49 @@ const DELIM_UPDATE = [',', ' AND ']
17
24
 
18
25
  class DbLang {
19
26
 
27
+ static TP_SMALLINT = new DbTypeArithmeticInt ({name: 'SMALLINT', bytes: 2})
28
+ static TP_INT = new DbTypeArithmeticInt ({name: 'INT', bytes: 4})
29
+ static TP_BIGINT = new DbTypeArithmeticInt ({name: 'BIGINT', bytes: 8})
30
+ static TP_REAL = new DbTypeArithmeticFloat ({name: 'REAL'})
31
+ static TP_NUMERIC = new DbTypeArithmeticFixed ({name: 'NUMERIC'})
32
+ static TP_CHAR = new DbTypeCharacter ({name: 'CHAR'})
33
+ static TP_VARCHAR = new DbTypeCharacter ({name: 'VARCHAR'})
34
+
35
+ getTypeDefinition (name) {
36
+
37
+ name = name.toUpperCase ()
38
+
39
+ switch (name) {
40
+
41
+ case 'INT':
42
+ case 'INTEGER':
43
+ return DbLang.TP_INT
44
+
45
+ case 'BIGINT':
46
+ return DbLang.TP_BIGINT
47
+
48
+ case 'SMALLINT':
49
+ return DbLang.TP_SMALLINT
50
+
51
+ case 'CHAR':
52
+ return DbLang.TP_CHAR
53
+
54
+ case 'VARCHAR':
55
+ return DbLang.TP_VARCHAR
56
+
57
+ case 'NUMERIC':
58
+ case 'DECIMAL':
59
+ return DbLang.TP_NUMERIC
60
+
61
+ case 'REAL':
62
+ return DbLang.TP_REAL
63
+
64
+ }
65
+
66
+ return new DbType ({name})
67
+
68
+ }
69
+
20
70
  getDbObjectClass (o) {
21
71
 
22
72
  if (o == null) throw Error ('Empty definition')
@@ -35,6 +85,63 @@ class DbLang {
35
85
 
36
86
  }
37
87
 
88
+ isEqualColumnDefault (column, existing) {
89
+
90
+ return column.default == existing.default
91
+
92
+ }
93
+
94
+ isAdequateColumnType (typeAsIs, typeToBe) {
95
+
96
+ if (typeToBe instanceof DbTypeArithmeticInt && typeAsIs instanceof DbTypeArithmeticInt) return (
97
+ typeAsIs.isSigned === typeToBe.isSigned &&
98
+ typeAsIs.bytes >= typeToBe.bytes
99
+ )
100
+
101
+ return typeAsIs.name === typeToBe.name
102
+
103
+ }
104
+
105
+ isAdequateColumnTypeDim (asIs, toBe) {
106
+
107
+ const typeToBe = this.getTypeDefinition (toBe.type), typeAsIs = this.getTypeDefinition (asIs.type)
108
+
109
+ if (typeToBe !== typeAsIs && !this.isAdequateColumnType (typeAsIs, typeToBe)) return false
110
+
111
+ if (toBe.size > 0 && toBe.size > asIs.size) return false
112
+
113
+ if (typeToBe instanceof DbTypeArithmeticFixed && toBe.scale > asIs.scale) return false
114
+
115
+ return true
116
+
117
+ }
118
+
119
+ compareColumns (asIs, toBe) {
120
+
121
+ const diff = []
122
+
123
+ if (asIs.nullable !== toBe.nullable) diff.push ('nullable')
124
+
125
+ if (!this.isEqualColumnDefault (asIs, toBe)) diff.push ('default')
126
+
127
+ if (!this.isAdequateColumnTypeDim (asIs, toBe)) diff.push ('typeDim')
128
+
129
+ return diff
130
+
131
+ }
132
+
133
+ getRequiredMutation (asIs, toBe) {
134
+
135
+ return null
136
+
137
+ }
138
+
139
+ getRequiredColumnMutation (asIs, toBe) {
140
+
141
+ return asIs.diff.length === 0 ? null : 'alter-column'
142
+
143
+ }
144
+
38
145
  quoteName (s) {
39
146
 
40
147
  return CH_QQ + QQ_ESC.escape (s) + CH_QQ
@@ -71,14 +178,8 @@ class DbLang {
71
178
 
72
179
  }
73
180
 
74
- }
75
-
76
- getCanonicalTypeName (type) {
77
-
78
- return type.toUpperCase ()
79
-
80
181
  }
81
-
182
+
82
183
  getDbObjectName (o) {
83
184
 
84
185
  const {schemaName, localName} = o
@@ -91,13 +192,18 @@ class DbLang {
91
192
 
92
193
  getDbColumnTypeDim (col) {
93
194
 
94
- if (!('size' in col)) return col.type
195
+ const {type, size} = col; if (size == null) return type
95
196
 
96
- let s = col.type + '(' + col.size
197
+ let s = `${type}(${size}`
97
198
 
98
- if ('scale' in col) s += ',' + col.scale
199
+ const {scale} = col; if (scale != null) {
200
+ s += ','
201
+ s += scale
202
+ }
203
+
204
+ s += ')'
99
205
 
100
- return s + ')'
206
+ return s
101
207
 
102
208
  }
103
209
 
@@ -1,5 +1,28 @@
1
+ const DbRelation = require ('../model/DbRelation.js')
2
+
1
3
  const EventEmitter = require ('events')
2
4
 
5
+ const OBJECT_ACTIONS = [
6
+ 'create',
7
+ 'alter',
8
+ 'migrate',
9
+ 'recreate',
10
+ ]
11
+
12
+ const COLUMN_ACTIONS = [
13
+ 'add-column',
14
+ 'alter-column',
15
+ 'migrate-column',
16
+ ]
17
+
18
+ const add = (toDo, action, object) => {
19
+
20
+ if (!toDo.has (action)) toDo.set (action, [])
21
+
22
+ toDo.get (action).push (object)
23
+
24
+ }
25
+
3
26
  class DbMigrationPlan extends EventEmitter {
4
27
 
5
28
  constructor (db) {
@@ -10,15 +33,91 @@ class DbMigrationPlan extends EventEmitter {
10
33
  this.lang = db.lang
11
34
  this.model = db.model
12
35
  this.toBe = db.model.map
13
- this.asIs = new Map ()
36
+
37
+ db.lang.migrationPlan = this
14
38
 
15
39
  this.on ('existing', o => this.asIs.set (o.name, o))
40
+
41
+ this.toDo = new Map
42
+
43
+ for (const action of OBJECT_ACTIONS)
44
+
45
+ this.on (action, object => add (
46
+ this.toDo,
47
+ action, object))
48
+
49
+ for (const action of COLUMN_ACTIONS)
50
+
51
+ this.on (action, column => add (
52
+ this.asIs.get (column.relation.name).toDo,
53
+ action, column))
54
+
55
+ }
56
+
57
+ compareRelation (asIs, toBe) {
58
+
59
+ const {lang} = this, {columns} = toBe, existingColumns = asIs.columns
60
+
61
+ for (const [name, column] of Object.entries (columns)) {
62
+
63
+ if (name in existingColumns) {
64
+
65
+ const existingColumn = existingColumns [name]
66
+
67
+ existingColumn.diff = lang.compareColumns (existingColumn, column)
68
+
69
+ const action = lang.getRequiredColumnMutation (existingColumn, column)
70
+
71
+ if (action !== null) this.emit (action, column)
72
+
73
+ }
74
+ else {
75
+
76
+ this.emit ('add-column', column)
77
+
78
+ }
79
+
80
+ }
81
+
82
+ }
83
+
84
+ compareObject (asIs, toBe) {
85
+
86
+ if (asIs.constructor === toBe.constructor && toBe instanceof DbRelation)
87
+
88
+ this.compareRelation (asIs, toBe)
89
+
90
+ return this.lang.getRequiredMutation (asIs, toBe)
91
+
92
+ }
93
+
94
+ inspectStructure () {
95
+
96
+ const {asIs} = this; if (!asIs) throw Error ('Existing database objects not discovered, call loadStructure () first')
97
+
98
+ const {lang} = this, hardClasses = lang.getDbObjectClassesToDiscover ()
99
+
100
+ for (const [name, object] of this.toBe.entries ()) {
101
+
102
+ const action =
103
+
104
+ !hardClasses.includes (object.constructor) ? 'recreate' :
105
+
106
+ !asIs.has (name) ? 'create' :
107
+
108
+ this.compareObject (asIs.get (name), object)
109
+
110
+ if (action !== null) this.emit (action, object)
111
+
112
+ }
16
113
 
17
114
  }
18
115
 
19
116
  async loadStructure () {
117
+
118
+ this.asIs = new Map ()
20
119
 
21
- return Promise.all (this.db.lang.getDbObjectClassesToDiscover ().map (type => this.loadExistingObjects (type)))
120
+ return Promise.all (this.lang.getDbObjectClassesToDiscover ().map (type => this.loadExistingObjects (type)))
22
121
 
23
122
  }
24
123
 
@@ -33,11 +132,16 @@ class DbMigrationPlan extends EventEmitter {
33
132
  s.on ('error', fail)
34
133
 
35
134
  s.on ('end', ok)
135
+
136
+ s.on ('data', object => {
36
137
 
37
- s.on ('data', table => this.emit (
38
- toBe.has (table.name) ? 'existing' : 'unknown',
39
- table
40
- ))
138
+ object.toDo = new Map
139
+
140
+ const event = toBe.has (object.name) ? 'existing' : 'unknown'
141
+
142
+ this.emit (event, object)
143
+
144
+ })
41
145
 
42
146
  })
43
147
 
@@ -198,7 +198,9 @@ class DbColumn {
198
198
 
199
199
  if (this.type) {
200
200
 
201
- this.type = lang.getCanonicalTypeName (this.type)
201
+ this.typeDef = lang.getTypeDefinition (this.type)
202
+
203
+ this.type = this.typeDef.name
202
204
 
203
205
  this.typeDim = lang.getDbColumnTypeDim (this)
204
206
 
@@ -0,0 +1,11 @@
1
+ class DbType {
2
+
3
+ constructor (o) {
4
+
5
+ for (const k in o) this [k] = o [k]
6
+
7
+ }
8
+
9
+ }
10
+
11
+ module.exports = DbType
@@ -0,0 +1,13 @@
1
+ const DbType = require ('./DbType.js')
2
+
3
+ class DbTypeArithmetic extends DbType {
4
+
5
+ constructor (o) {
6
+
7
+ super (o)
8
+
9
+ }
10
+
11
+ }
12
+
13
+ module.exports = DbTypeArithmetic
@@ -0,0 +1,13 @@
1
+ const DbTypeArithmetic = require ('./DbTypeArithmetic.js')
2
+
3
+ class DbTypeArithmeticFixed extends DbTypeArithmetic {
4
+
5
+ constructor (o) {
6
+
7
+ super (o)
8
+
9
+ }
10
+
11
+ }
12
+
13
+ module.exports = DbTypeArithmeticFixed
@@ -0,0 +1,13 @@
1
+ const DbTypeArithmetic = require ('./DbTypeArithmetic.js')
2
+
3
+ class DbTypeArithmeticFloat extends DbTypeArithmetic {
4
+
5
+ constructor (o) {
6
+
7
+ super (o)
8
+
9
+ }
10
+
11
+ }
12
+
13
+ module.exports = DbTypeArithmeticFloat
@@ -0,0 +1,15 @@
1
+ const DbTypeArithmetic = require ('./DbTypeArithmetic.js')
2
+
3
+ class DbTypeArithmeticInt extends DbTypeArithmetic {
4
+
5
+ constructor (o) {
6
+
7
+ super (o)
8
+
9
+ if (!('isSigned' in this)) this.isSigned = true
10
+
11
+ }
12
+
13
+ }
14
+
15
+ module.exports = DbTypeArithmeticInt
@@ -0,0 +1,13 @@
1
+ const DbType = require ('./DbType.js')
2
+
3
+ class DbTypeCharacter extends DbType {
4
+
5
+ constructor (o) {
6
+
7
+ super (o)
8
+
9
+ }
10
+
11
+ }
12
+
13
+ module.exports = DbTypeCharacter
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "doix-db",
3
- "version": "0.0.36",
3
+ "version": "0.0.41",
4
4
  "description": "Shared database related code for doix",
5
5
  "main": "index.js",
6
6
  "files": [