doix-db 1.0.22 → 1.0.25

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
@@ -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/DbCall.js CHANGED
@@ -89,6 +89,8 @@ class DbCall extends EventEmitter {
89
89
  this.params = params
90
90
  this.options = options
91
91
 
92
+ this.on ('error', error => this.error = error)
93
+
92
94
  }
93
95
 
94
96
  get objectMode () {
@@ -242,7 +244,7 @@ class DbCall extends EventEmitter {
242
244
  }
243
245
  catch (error) {
244
246
 
245
- this.emit ('error', this.error = error)
247
+ this.emit ('error', error)
246
248
 
247
249
  throw error
248
250
 
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,14 @@ class DbClient extends EventEmitter {
33
34
  this.uuid = randomUUID ()
34
35
 
35
36
  }
37
+
38
+ toCsv (options) {
39
+
40
+ const {lang} = this
41
+
42
+ return new DbCsvPrinter ({...options, lang})
43
+
44
+ }
36
45
 
37
46
  createMigrationPlan () {
38
47
 
@@ -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 = new DbTypeArithmeticInt ({name: 'SMALLINT', bytes: 2})
31
- static TP_INT = new DbTypeArithmeticInt ({name: 'INT', bytes: 4})
32
- static TP_BIGINT = new DbTypeArithmeticInt ({name: 'BIGINT', bytes: 8})
33
- static TP_REAL = new DbTypeArithmeticFloat ({name: 'REAL'})
34
- static TP_NUMERIC = new DbTypeArithmeticFixed ({name: 'NUMERIC'})
35
- static TP_CHAR = new DbTypeCharacter ({name: 'CHAR'})
36
- static TP_VARCHAR = new DbTypeCharacter ({name: '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})
@@ -0,0 +1,13 @@
1
+ const DbTypeTemporal = require ('./DbTypeTemporal.js')
2
+
3
+ class DbTypeDate extends DbTypeTemporal {
4
+
5
+ constructor (o) {
6
+
7
+ super (o)
8
+
9
+ }
10
+
11
+ }
12
+
13
+ module.exports = DbTypeDate
@@ -0,0 +1,13 @@
1
+ const DbType = require ('./DbType.js')
2
+
3
+ class DbTypeTemporal extends DbType {
4
+
5
+ constructor (o) {
6
+
7
+ super (o)
8
+
9
+ }
10
+
11
+ }
12
+
13
+ module.exports = DbTypeTemporal
@@ -0,0 +1,13 @@
1
+ const DbTypeTemporal = require ('./DbTypeTemporal.js')
2
+
3
+ class DbTypeTimestamp extends DbTypeTemporal {
4
+
5
+ constructor (o) {
6
+
7
+ super (o)
8
+
9
+ }
10
+
11
+ }
12
+
13
+ module.exports = DbTypeTimestamp
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "doix-db",
3
- "version": "1.0.22",
3
+ "version": "1.0.25",
4
4
  "description": "Shared database related code for doix",
5
5
  "main": "index.js",
6
6
  "files": [