doix-db 1.0.23 → 1.0.26
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 +3 -0
- package/lib/DbClient.js +17 -0
- package/lib/DbCsvPrinter.js +239 -0
- package/lib/DbLang.js +27 -8
- package/lib/model/types/DbTypeDate.js +13 -0
- package/lib/model/types/DbTypeTemporal.js +13 -0
- package/lib/model/types/DbTypeTimestamp.js +13 -0
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -4,6 +4,7 @@ module.exports = {
|
|
|
4
4
|
DbClient: require ('./lib/DbClient.js'),
|
|
5
5
|
DbPool: require ('./lib/DbPool.js'),
|
|
6
6
|
DbLang: require ('./lib/DbLang.js'),
|
|
7
|
+
DbCsvPrinter: require ('./lib/DbCsvPrinter.js'),
|
|
7
8
|
DbColumn: require ('./lib/model/DbColumn.js'),
|
|
8
9
|
DbReference: require ('./lib/model/DbReference.js'),
|
|
9
10
|
DbObjectMerger: require ('./lib/model/DbObjectMerger.js'),
|
|
@@ -23,6 +24,8 @@ module.exports = {
|
|
|
23
24
|
DbTypeArithmeticFloat: require ('./lib/model/types/DbTypeArithmeticFloat.js'),
|
|
24
25
|
DbTypeArithmeticInt: require ('./lib/model/types/DbTypeArithmeticInt.js'),
|
|
25
26
|
DbTypeCharacter: require ('./lib/model/types/DbTypeCharacter.js'),
|
|
27
|
+
DbTypeDate: require ('./lib/model/types/DbTypeDate.js'),
|
|
28
|
+
DbTypeTimestamp: require ('./lib/model/types/DbTypeTimestamp.js'),
|
|
26
29
|
|
|
27
30
|
DbMigrationPlan:require ('./lib/migration/DbMigrationPlan.js'),
|
|
28
31
|
DbQuery: require ('./lib/query/DbQuery.js'),
|
package/lib/DbClient.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const EventEmitter = require ('events')
|
|
2
2
|
const {randomUUID} = require ('crypto')
|
|
3
3
|
|
|
4
|
+
const DbCsvPrinter = require ('./DbCsvPrinter.js')
|
|
4
5
|
const DbCall = require ('./DbCall.js')
|
|
5
6
|
const DbQuery = require ('./query/DbQuery.js')
|
|
6
7
|
const DbMigrationPlan = require ('./migration/DbMigrationPlan.js')
|
|
@@ -33,6 +34,22 @@ class DbClient extends EventEmitter {
|
|
|
33
34
|
this.uuid = randomUUID ()
|
|
34
35
|
|
|
35
36
|
}
|
|
37
|
+
|
|
38
|
+
async createTempTable (table, options) {
|
|
39
|
+
|
|
40
|
+
if (typeof table === 'string') table = this.model.find (table)
|
|
41
|
+
|
|
42
|
+
return this.do (this.lang.genCreateTempTable (table, options))
|
|
43
|
+
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
toCsv (options) {
|
|
47
|
+
|
|
48
|
+
const {lang} = this
|
|
49
|
+
|
|
50
|
+
return new DbCsvPrinter ({...options, lang})
|
|
51
|
+
|
|
52
|
+
}
|
|
36
53
|
|
|
37
54
|
createMigrationPlan () {
|
|
38
55
|
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
const DbColumn = require ('./model/DbColumn.js')
|
|
2
|
+
const DbTypeArithmetic = require ('./model/types/DbTypeArithmetic.js')
|
|
3
|
+
const DbTypeArithmeticInt = require ('./model/types/DbTypeArithmeticInt.js')
|
|
4
|
+
const DbTypeArithmeticFixed = require ('./model/types/DbTypeArithmeticFixed.js')
|
|
5
|
+
const DbTypeCharacter = require ('./model/types/DbTypeCharacter.js')
|
|
6
|
+
const DbTypeTemporal = require ('./model/types/DbTypeTemporal.js')
|
|
7
|
+
const DbTypeDate = require ('./model/types/DbTypeDate.js')
|
|
8
|
+
const DbTypeTimestamp = require ('./model/types/DbTypeTimestamp.js')
|
|
9
|
+
const {Transform} = require ('stream')
|
|
10
|
+
const stringEscape = require ('string-escape-map')
|
|
11
|
+
const CH_QQ = '"', QQ_ESC = new stringEscape ([[CH_QQ, CH_QQ + CH_QQ]])
|
|
12
|
+
|
|
13
|
+
const FMT_ISO_DATE = new Intl.DateTimeFormat ('sv', {
|
|
14
|
+
year: 'numeric',
|
|
15
|
+
month: '2-digit',
|
|
16
|
+
day: '2-digit',
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
const FMT_ISO_TIMESTAMP = new Intl.DateTimeFormat ('sv', {
|
|
20
|
+
year: 'numeric',
|
|
21
|
+
month: '2-digit',
|
|
22
|
+
day: '2-digit',
|
|
23
|
+
hour: '2-digit',
|
|
24
|
+
minute: '2-digit',
|
|
25
|
+
second: '2-digit',
|
|
26
|
+
fractionalSecondDigits: 3
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
class DbCsvPrinter extends Transform {
|
|
30
|
+
|
|
31
|
+
constructor (options = {}) {
|
|
32
|
+
|
|
33
|
+
let {table, columns, lang, NULL} = options
|
|
34
|
+
|
|
35
|
+
super ({writableObjectMode: true})
|
|
36
|
+
|
|
37
|
+
this.NULL = typeof NULL === 'string' ? NULL : ''
|
|
38
|
+
|
|
39
|
+
if (!columns) {
|
|
40
|
+
if (!table) throw Error (`Either table or columns must be defined`)
|
|
41
|
+
columns = Object.values (table.columns)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (lang) {
|
|
45
|
+
|
|
46
|
+
this.lang = lang
|
|
47
|
+
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
|
|
51
|
+
if (table) {
|
|
52
|
+
this.lang = table.model.lang
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
throw Error (`Lang not defined`)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!Array.isArray (columns)) columns = Object.entries (columns).map (([name, def]) => {
|
|
61
|
+
|
|
62
|
+
const col = new DbColumn (def)
|
|
63
|
+
|
|
64
|
+
col.name = name
|
|
65
|
+
|
|
66
|
+
return col
|
|
67
|
+
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
const {length} = columns; for (let i = 0; i < length; i ++) {
|
|
71
|
+
|
|
72
|
+
const col = columns [i];
|
|
73
|
+
|
|
74
|
+
if (typeof col === 'string') {
|
|
75
|
+
|
|
76
|
+
if (!table) throw Error ('To pass columns by name only, the table must be provided')
|
|
77
|
+
|
|
78
|
+
if (!(col in table.columns)) throw Error (`${table.name}.${col} not found`)
|
|
79
|
+
|
|
80
|
+
columns [i] = table.columns [col]
|
|
81
|
+
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (!('typeDef' in columns [i])) columns [i].setLang (this.lang)
|
|
85
|
+
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
this.columns = columns
|
|
89
|
+
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
_transform (r, _, callback) {
|
|
93
|
+
|
|
94
|
+
const {columns} = this, {length} = columns
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
|
|
98
|
+
let s = ''; for (let i = 0; i < length; i ++) {
|
|
99
|
+
|
|
100
|
+
if (i !== 0) s += ','
|
|
101
|
+
|
|
102
|
+
const column = columns [i], {name, typeDef} = column
|
|
103
|
+
|
|
104
|
+
const value = r [name], v = value == null ? column.default : value
|
|
105
|
+
|
|
106
|
+
switch (v) {
|
|
107
|
+
case Number.POSITIVE_INFINITY:
|
|
108
|
+
case Number.NEGATIVE_INFINITY:
|
|
109
|
+
throw Error (`${column.name}: infinite values not supported`)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (v == null) {
|
|
113
|
+
|
|
114
|
+
if (!column.nullable) throw Error (`${name} doesn't allow null values`)
|
|
115
|
+
|
|
116
|
+
s += this.NULL
|
|
117
|
+
|
|
118
|
+
}
|
|
119
|
+
else if (typeof v === 'boolean') {
|
|
120
|
+
|
|
121
|
+
s += v ? '1' : '0'
|
|
122
|
+
|
|
123
|
+
}
|
|
124
|
+
else if (typeDef instanceof DbTypeCharacter) {
|
|
125
|
+
|
|
126
|
+
s += CH_QQ
|
|
127
|
+
s += QQ_ESC.escape (String (v))
|
|
128
|
+
s += CH_QQ
|
|
129
|
+
|
|
130
|
+
}
|
|
131
|
+
else if (typeDef instanceof DbTypeArithmetic) {
|
|
132
|
+
|
|
133
|
+
const n = Number (v)
|
|
134
|
+
|
|
135
|
+
if (typeDef instanceof DbTypeArithmeticInt) {
|
|
136
|
+
|
|
137
|
+
if (!Number.isInteger (Number (v))) throw Error (`${column.name} must be integer, found ${value}`)
|
|
138
|
+
|
|
139
|
+
s += v
|
|
140
|
+
|
|
141
|
+
}
|
|
142
|
+
else if (typeDef instanceof DbTypeArithmeticFixed) {
|
|
143
|
+
|
|
144
|
+
if (!Number.isFinite (n)) throw Error (`${column.name} must be a finite number, found ${value}`)
|
|
145
|
+
|
|
146
|
+
s += n.toFixed (column.scale)
|
|
147
|
+
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
|
|
151
|
+
if (Number.isNaN (n)) throw Error (`${column.name} must be a number, found ${value}`)
|
|
152
|
+
|
|
153
|
+
s += v
|
|
154
|
+
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
}
|
|
158
|
+
else if (typeDef instanceof DbTypeTemporal) {
|
|
159
|
+
|
|
160
|
+
const isDate = typeDef instanceof DbTypeDate; if (!isDate && !(typeDef instanceof DbTypeTimestamp)) throw Error (`Don't know how to format ${column.name}`)
|
|
161
|
+
|
|
162
|
+
let d; if (typeof v === 'string') {
|
|
163
|
+
|
|
164
|
+
d = v
|
|
165
|
+
|
|
166
|
+
}
|
|
167
|
+
else if (v instanceof Date) {
|
|
168
|
+
|
|
169
|
+
d = (isDate ? FMT_ISO_DATE : FMT_ISO_TIMESTAMP).format (v)
|
|
170
|
+
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
|
|
174
|
+
throw Error (`${column.name} must be a date/time, found ${value}`)
|
|
175
|
+
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (isDate) {
|
|
179
|
+
|
|
180
|
+
const {length} = d
|
|
181
|
+
|
|
182
|
+
if (length < 10) {
|
|
183
|
+
throw Error (`${column.name} must be a date, found ${value}`)
|
|
184
|
+
}
|
|
185
|
+
else if (length === 10) {
|
|
186
|
+
s += d
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
s += d.slice (0, 10)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
|
|
195
|
+
const {length} = d, {scale} = column
|
|
196
|
+
|
|
197
|
+
if (length < 19) {
|
|
198
|
+
|
|
199
|
+
throw Error (`${column.name} must be a timestamp, found ${value}`)
|
|
200
|
+
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
|
|
204
|
+
s += d.slice (0, 19)
|
|
205
|
+
|
|
206
|
+
if (scale > 0 && length > 20) {
|
|
207
|
+
|
|
208
|
+
s += '.'
|
|
209
|
+
s += d.slice (20, 20 + scale)
|
|
210
|
+
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
|
|
220
|
+
throw Error (`Don't know how to format ${column.name}`)
|
|
221
|
+
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
s += '\n'; callback (null, s)
|
|
227
|
+
|
|
228
|
+
}
|
|
229
|
+
catch (err) {
|
|
230
|
+
|
|
231
|
+
callback (err)
|
|
232
|
+
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
module.exports = DbCsvPrinter
|
package/lib/DbLang.js
CHANGED
|
@@ -7,11 +7,12 @@ const DbProcedure = require ('./model/DbProcedure.js')
|
|
|
7
7
|
const DbFunction = require ('./model/DbFunction.js')
|
|
8
8
|
|
|
9
9
|
const DbType = require ('./model/types/DbType.js')
|
|
10
|
-
const DbTypeArithmetic = require ('./model/types/DbTypeArithmetic.js')
|
|
11
10
|
const DbTypeArithmeticFixed = require ('./model/types/DbTypeArithmeticFixed.js')
|
|
12
11
|
const DbTypeArithmeticFloat = require ('./model/types/DbTypeArithmeticFloat.js')
|
|
13
12
|
const DbTypeArithmeticInt = require ('./model/types/DbTypeArithmeticInt.js')
|
|
14
13
|
const DbTypeCharacter = require ('./model/types/DbTypeCharacter.js')
|
|
14
|
+
const DbTypeDate = require ('./model/types/DbTypeDate.js')
|
|
15
|
+
const DbTypeTimestamp = require ('./model/types/DbTypeTimestamp.js')
|
|
15
16
|
|
|
16
17
|
const CH_Q = "'", CH_QQ = '"'
|
|
17
18
|
|
|
@@ -27,13 +28,15 @@ const DELIM_UPDATE = [',', ' AND ']
|
|
|
27
28
|
|
|
28
29
|
class DbLang {
|
|
29
30
|
|
|
30
|
-
static TP_SMALLINT
|
|
31
|
-
static TP_INT
|
|
32
|
-
static TP_BIGINT
|
|
33
|
-
static TP_REAL
|
|
34
|
-
static TP_NUMERIC
|
|
35
|
-
static TP_CHAR
|
|
36
|
-
static TP_VARCHAR
|
|
31
|
+
static TP_SMALLINT = new DbTypeArithmeticInt ({name: 'SMALLINT', bytes: 2})
|
|
32
|
+
static TP_INT = new DbTypeArithmeticInt ({name: 'INT', bytes: 4})
|
|
33
|
+
static TP_BIGINT = new DbTypeArithmeticInt ({name: 'BIGINT', bytes: 8})
|
|
34
|
+
static TP_REAL = new DbTypeArithmeticFloat ({name: 'REAL'})
|
|
35
|
+
static TP_NUMERIC = new DbTypeArithmeticFixed ({name: 'NUMERIC'})
|
|
36
|
+
static TP_CHAR = new DbTypeCharacter ({name: 'CHAR'})
|
|
37
|
+
static TP_VARCHAR = new DbTypeCharacter ({name: 'VARCHAR'})
|
|
38
|
+
static TP_DATE = new DbTypeDate ({name: 'DATE'})
|
|
39
|
+
static TP_TIMESTAMP = new DbTypeTimestamp ({name: 'TIMESTAMP'})
|
|
37
40
|
|
|
38
41
|
getTypeDefinition (name) {
|
|
39
42
|
|
|
@@ -64,6 +67,12 @@ class DbLang {
|
|
|
64
67
|
case 'REAL':
|
|
65
68
|
return DbLang.TP_REAL
|
|
66
69
|
|
|
70
|
+
case 'DATE':
|
|
71
|
+
return DbLang.TP_DATE
|
|
72
|
+
|
|
73
|
+
case 'TIMESTAMP':
|
|
74
|
+
return DbLang.TP_TIMESTAMP
|
|
75
|
+
|
|
67
76
|
}
|
|
68
77
|
|
|
69
78
|
return new DbType ({name})
|
|
@@ -467,6 +476,16 @@ class DbLang {
|
|
|
467
476
|
|
|
468
477
|
}
|
|
469
478
|
|
|
479
|
+
genCreateTempTable ({qName, columns}, options = {}) {
|
|
480
|
+
|
|
481
|
+
let sql = 'CREATE TEMPORARY TABLE '
|
|
482
|
+
|
|
483
|
+
if (options.onlyIfMissing) sql += 'IF NOT EXISTS '
|
|
484
|
+
|
|
485
|
+
return sql + qName + ' (' + Object.values (columns).map (c => this.genColumnDefinition (c)) + ')'
|
|
486
|
+
|
|
487
|
+
}
|
|
488
|
+
|
|
470
489
|
getTriggerName (table, i) {
|
|
471
490
|
|
|
472
491
|
return table.name + '__trg_' + i.toString ().padStart ((table.triggers.length - 1).toString ().length, '0')
|