ffc-pay-etl-framework 1.4.1 → 1.4.2-beta.135
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/.npmignore +26 -0
- package/app/database-connections/index.js +7 -0
- package/app/{database_connections/postgresDatabaseConnection.js → database-connections/postgres-database-connection.js} +2 -2
- package/app/{database_connections/providedConnection.js → database-connections/provided-connection.js} +2 -2
- package/app/destinations/{consoleDestination.js → console-destination.js} +2 -2
- package/app/destinations/csv-file-destination.js +94 -0
- package/app/destinations/index.js +4 -4
- package/app/destinations/{postgresDestination.js → postgres-destination.js} +11 -9
- package/app/destinations/{sqlFileDestination.js → sql-file-destination.js} +5 -18
- package/app/lib/index.js +41 -44
- package/app/lib/{rowMetaData.js → row-meta-data.js} +3 -3
- package/app/loaders/{csvloader.js → csv-loader.js} +12 -12
- package/app/loaders/index.js +1 -1
- package/app/misc/index.js +5 -0
- package/app/misc/{postgresSQLTask.js → postgres-sql-task.js} +3 -9
- package/app/transformers/{fakerTransformer.js → faker-transformer.js} +5 -5
- package/app/transformers/index.js +3 -3
- package/app/transformers/{stringReplaceTransformer.js → string-replace-transformer.js} +8 -5
- package/app/transformers/{toUpperCaseTransformer.js → to-upper-case-transformer.js} +8 -6
- package/app/validators/index.js +3 -3
- package/app/validators/{multiToolValidator.js → multi-tool-validator.js} +7 -6
- package/app/validators/{requiredValidator.js → required-validator.js} +3 -3
- package/app/validators/{uniqueValidator.js → unique-validator.js} +15 -10
- package/azure-pipelines.yml +45 -0
- package/index.js +3 -1
- package/jest.config.js +42 -0
- package/jest.setup.js +2 -0
- package/package-lock.json +7990 -0
- package/package.json +5 -33
- package/app/database_connections/index.js +0 -7
- package/app/destinations/csvFileDestination.js +0 -75
package/.npmignore
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Ignore dotfiles explicitly by name
|
|
2
|
+
/.all-contributorsrc
|
|
3
|
+
/.dockerignore
|
|
4
|
+
/.gitignore
|
|
5
|
+
/.snyk
|
|
6
|
+
/CODE_OF_CONDUCT.md
|
|
7
|
+
/CONTRIBUTING.md
|
|
8
|
+
/eslint.config.js
|
|
9
|
+
/ISSUE_TEMPLATE.md
|
|
10
|
+
/Jenkinsfile
|
|
11
|
+
/LICENSE.md
|
|
12
|
+
/PULL_REQUEST_TEMPLATE.md
|
|
13
|
+
/sonar-project.properties
|
|
14
|
+
/snyk_report.html
|
|
15
|
+
/snyk-error.log
|
|
16
|
+
/snyk-monitor-result.json
|
|
17
|
+
/snyk-result.json
|
|
18
|
+
|
|
19
|
+
# Ignore folders recursively
|
|
20
|
+
__mocks__/
|
|
21
|
+
.devcontainer/
|
|
22
|
+
.github/
|
|
23
|
+
jest/
|
|
24
|
+
test/
|
|
25
|
+
snyk-cli/
|
|
26
|
+
test-output/
|
|
@@ -13,7 +13,7 @@ const debug = require('debug')('connection')
|
|
|
13
13
|
* @param {Object} options.port
|
|
14
14
|
* @returns Connection
|
|
15
15
|
*/
|
|
16
|
-
async function
|
|
16
|
+
async function postgresDatabaseConnection (options) {
|
|
17
17
|
const connectionname = options.connectionname
|
|
18
18
|
const username = options.username
|
|
19
19
|
const password = options.password
|
|
@@ -43,5 +43,5 @@ async function PostgresDatabaseConnection (options) {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
module.exports = {
|
|
46
|
-
PostgresDatabaseConnection
|
|
46
|
+
PostgresDatabaseConnection: postgresDatabaseConnection
|
|
47
47
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* @param {Object} options.sequelize
|
|
6
6
|
* @returns Connection
|
|
7
7
|
*/
|
|
8
|
-
async function
|
|
8
|
+
async function providedConnection (options) {
|
|
9
9
|
const connectionname = options.connectionname
|
|
10
10
|
const sequelize = options.sequelize
|
|
11
11
|
return {
|
|
@@ -15,5 +15,5 @@ async function ProvidedConnection (options) {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
module.exports = {
|
|
18
|
-
ProvidedConnection
|
|
18
|
+
ProvidedConnection: providedConnection
|
|
19
19
|
}
|
|
@@ -6,7 +6,7 @@ const { Writable } = require('node:stream')
|
|
|
6
6
|
* @param {String} options.includeErrors
|
|
7
7
|
* @returns Writable
|
|
8
8
|
*/
|
|
9
|
-
function
|
|
9
|
+
function consoleDestination (options) {
|
|
10
10
|
const includeErrors = options.includeErrors
|
|
11
11
|
const writable = new Writable({
|
|
12
12
|
objectMode: true,
|
|
@@ -34,5 +34,5 @@ function ConsoleDestination (options) {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
module.exports = {
|
|
37
|
-
ConsoleDestination
|
|
37
|
+
ConsoleDestination: consoleDestination
|
|
38
38
|
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
const EventEmitter = require('node:events')
|
|
2
|
+
const util = require('node:util')
|
|
3
|
+
const { Writable } = require('node:stream')
|
|
4
|
+
const fs = require('node:fs')
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
* @param {Object} options
|
|
9
|
+
* @param {String} options.fileName
|
|
10
|
+
* @param {Boolean} options.headers
|
|
11
|
+
* @param {Boolean} options.includeErrors
|
|
12
|
+
* @param {Boolean} options.quotationMarks
|
|
13
|
+
* @returns Writable
|
|
14
|
+
*/
|
|
15
|
+
function csvFileDestination (options) {
|
|
16
|
+
EventEmitter.call(this)
|
|
17
|
+
let lastChunk
|
|
18
|
+
const fileName = options.fileName
|
|
19
|
+
const headers = options.headers
|
|
20
|
+
const includeErrors = options.includeErrors
|
|
21
|
+
const quotationMarks = options.quotationMarks
|
|
22
|
+
|
|
23
|
+
let fileHandle
|
|
24
|
+
try {
|
|
25
|
+
fileHandle = fs.openSync(fileName, 'w+')
|
|
26
|
+
} catch (error) {
|
|
27
|
+
throw new Error(`Failed to open file ${fileName}: ${error.message}`)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let headersWritten = false
|
|
31
|
+
|
|
32
|
+
const writable = new Writable({
|
|
33
|
+
objectMode: true,
|
|
34
|
+
write (chunk, _, callback) {
|
|
35
|
+
try {
|
|
36
|
+
if (!headersWritten && headers) {
|
|
37
|
+
if (quotationMarks) {
|
|
38
|
+
const quotedColumns = chunk._columns.map(c => `"${c}"`).join(',')
|
|
39
|
+
fs.writeSync(fileHandle, quotedColumns + '\n')
|
|
40
|
+
} else {
|
|
41
|
+
fs.writeSync(fileHandle, `${chunk._columns.join(',')}\n`)
|
|
42
|
+
}
|
|
43
|
+
headersWritten = true
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const errors = Array.isArray(chunk.errors) ? chunk.errors : []
|
|
47
|
+
|
|
48
|
+
if (errors.length === 0 || includeErrors) {
|
|
49
|
+
const line = chunk.map(c => `"${c}"`).join(',') + '\n'
|
|
50
|
+
fs.writeSync(fileHandle, line)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (this.tasks && Array.isArray(this.tasks)) {
|
|
54
|
+
this.tasks.forEach(task => task.write(chunk))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
lastChunk = chunk
|
|
58
|
+
callback()
|
|
59
|
+
} catch (err) {
|
|
60
|
+
callback(err)
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
final (callback) {
|
|
64
|
+
if (fileHandle) {
|
|
65
|
+
fs.closeSync(fileHandle)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
this.emit('result', lastChunk)
|
|
69
|
+
callback()
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
Object.assign(writable, {
|
|
74
|
+
setConnection: function (connection) {
|
|
75
|
+
this.connection = connection
|
|
76
|
+
}.bind(writable),
|
|
77
|
+
|
|
78
|
+
getConnectionName: function () {
|
|
79
|
+
return this.connection?.name
|
|
80
|
+
}.bind(writable),
|
|
81
|
+
|
|
82
|
+
setTasks: function (tasks) {
|
|
83
|
+
this.tasks = tasks
|
|
84
|
+
}.bind(writable)
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
return writable
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
util.inherits(csvFileDestination, EventEmitter)
|
|
91
|
+
|
|
92
|
+
module.exports = {
|
|
93
|
+
CSVFileDestination: csvFileDestination
|
|
94
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
const { ConsoleDestination } = require('./
|
|
2
|
-
const { SQLFileDestination, SQL_MODE } = require('./
|
|
3
|
-
const { CSVFileDestination } = require('./
|
|
4
|
-
const { PostgresDestination } = require('./
|
|
1
|
+
const { ConsoleDestination } = require('./console-destination')
|
|
2
|
+
const { SQLFileDestination, SQL_MODE } = require('./sql-file-destination')
|
|
3
|
+
const { CSVFileDestination } = require('./csv-file-destination')
|
|
4
|
+
const { PostgresDestination } = require('./postgres-destination')
|
|
5
5
|
|
|
6
6
|
module.exports = {
|
|
7
7
|
ConsoleDestination,
|
|
@@ -7,13 +7,15 @@ function isKeyWord (column) {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
function getMappingForColumn (mapping, column) {
|
|
10
|
-
if (mapping.length === 0) {
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
if (mapping.length === 0) {
|
|
11
|
+
return {}
|
|
12
|
+
}
|
|
13
|
+
const map = mapping.find(m => m.column === column)
|
|
14
|
+
return map || {}
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
function hasReturningColumns (mapping) {
|
|
16
|
-
return mapping.
|
|
18
|
+
return mapping.some(m => m.returning === true)
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
function getReturningColumns (mapping) {
|
|
@@ -33,9 +35,9 @@ function writeInsertStatement (columnMapping, table, chunk, schema, ignoredColum
|
|
|
33
35
|
.join(',')}) VALUES (${filteredColumns.map(column => {
|
|
34
36
|
const index = chunk._columns.indexOf(column)
|
|
35
37
|
const mapping = getMappingForColumn(columnMapping, column)
|
|
36
|
-
if (mapping?.targetType === 'number' && (isNaN(chunk[index]) || chunk[index] === '')) {
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
if (mapping?.targetType === 'number' && (Number.isNaN(Number(chunk[index])) || chunk[index] === '')) {
|
|
39
|
+
debug('Source data is not a number.')
|
|
40
|
+
return 0
|
|
39
41
|
}
|
|
40
42
|
if (mapping?.targetType === 'varchar' || mapping?.targetType === 'char') {
|
|
41
43
|
return `'${chunk[index]}'`
|
|
@@ -65,7 +67,7 @@ function writeInsertStatement (columnMapping, table, chunk, schema, ignoredColum
|
|
|
65
67
|
* @param {Array<String>} [options.ignoredColumns]
|
|
66
68
|
* @returns Transform
|
|
67
69
|
*/
|
|
68
|
-
function
|
|
70
|
+
function postgresDestination (options) {
|
|
69
71
|
EventEmitter.call(this)
|
|
70
72
|
const table = options.table
|
|
71
73
|
const connectionname = options.connectionname
|
|
@@ -130,7 +132,7 @@ function PostgresDestination (options) {
|
|
|
130
132
|
}
|
|
131
133
|
|
|
132
134
|
module.exports = {
|
|
133
|
-
PostgresDestination,
|
|
135
|
+
PostgresDestination: postgresDestination,
|
|
134
136
|
writeInsertStatement,
|
|
135
137
|
isKeyWord,
|
|
136
138
|
getMappingForColumn,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const { Writable } = require('node:stream')
|
|
2
|
-
const fs = require('fs')
|
|
2
|
+
const fs = require('node:fs')
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @enum {number}
|
|
@@ -19,12 +19,11 @@ const SQL_MODE = {
|
|
|
19
19
|
* @param {Boolean} options.includeErrors
|
|
20
20
|
* @returns Transform
|
|
21
21
|
*/
|
|
22
|
-
function
|
|
22
|
+
function sqlFileDestination (options) {
|
|
23
23
|
const fileName = options.fileName
|
|
24
24
|
const sqlMode = options.mode
|
|
25
25
|
const table = options.table
|
|
26
26
|
const mapping = options.mapping
|
|
27
|
-
const includeErrors = options.includeErrors
|
|
28
27
|
|
|
29
28
|
function writeInsertStatement (chunk) {
|
|
30
29
|
const statement = `INSERT INTO ${table} (${mapping.map(m => m.targetColumn)
|
|
@@ -41,21 +40,9 @@ function SQLFileDestination (options) {
|
|
|
41
40
|
const writable = new Writable({
|
|
42
41
|
objectMode: true,
|
|
43
42
|
write (chunk, _, callback) {
|
|
44
|
-
if (chunk.errors.length === 0) {
|
|
45
|
-
|
|
46
|
-
// @ts-ignore
|
|
47
|
-
if (chunk.errors.length === 0 | includeErrors) {
|
|
48
|
-
writeInsertStatement(chunk)
|
|
49
|
-
}
|
|
50
|
-
}
|
|
43
|
+
if (chunk.errors.length === 0 && sqlMode === SQL_MODE.INSERT_MODE) {
|
|
44
|
+
writeInsertStatement(chunk)
|
|
51
45
|
}
|
|
52
|
-
// TODO - Disabled because Sonar
|
|
53
|
-
// } else if (sqlMode === SQL_MODE.UPDATE_MODE){
|
|
54
|
-
// // @ts-ignore
|
|
55
|
-
// if(chunk.errors.length === 0 | includeErrors){
|
|
56
|
-
// writeUpdateStatement(chunk)
|
|
57
|
-
// }
|
|
58
|
-
// }
|
|
59
46
|
callback()
|
|
60
47
|
}
|
|
61
48
|
})
|
|
@@ -76,6 +63,6 @@ function SQLFileDestination (options) {
|
|
|
76
63
|
}
|
|
77
64
|
|
|
78
65
|
module.exports = {
|
|
79
|
-
SQLFileDestination,
|
|
66
|
+
SQLFileDestination: sqlFileDestination,
|
|
80
67
|
SQL_MODE
|
|
81
68
|
}
|
package/app/lib/index.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
1
|
const EventEmitter = require('node:events')
|
|
3
|
-
const
|
|
4
|
-
const { RowMetaData } = require('./rowMetaData')
|
|
2
|
+
const { RowMetaData } = require('./row-meta-data')
|
|
5
3
|
const { compose } = require('node:stream')
|
|
6
4
|
|
|
7
5
|
/**
|
|
@@ -18,89 +16,88 @@ const { compose } = require('node:stream')
|
|
|
18
16
|
*
|
|
19
17
|
* @returns Etl
|
|
20
18
|
*/
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
19
|
+
class Etl extends EventEmitter {
|
|
20
|
+
constructor () {
|
|
21
|
+
super()
|
|
22
|
+
this.store = []
|
|
23
|
+
this.beforeETLList = []
|
|
24
|
+
this.connectionList = []
|
|
25
|
+
this.validatorList = []
|
|
26
|
+
this.transformationList = []
|
|
27
|
+
this.destinationList = []
|
|
28
|
+
}
|
|
30
29
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return
|
|
30
|
+
loader (loader) {
|
|
31
|
+
this.loader = loader
|
|
32
|
+
return this
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
|
|
35
|
+
pump () {
|
|
37
36
|
this.beforeETLList.forEach(task => {
|
|
38
37
|
task.write({})
|
|
39
38
|
})
|
|
39
|
+
|
|
40
40
|
this.loader
|
|
41
41
|
.pump(this.loader)
|
|
42
42
|
.pipe(
|
|
43
43
|
compose(
|
|
44
44
|
RowMetaData(),
|
|
45
|
-
...
|
|
46
|
-
...
|
|
47
|
-
...
|
|
45
|
+
...this.validatorList,
|
|
46
|
+
...this.transformationList,
|
|
47
|
+
...this.destinationList.map(dl => dl.on('result', data => this.emit('result', data)))
|
|
48
48
|
)
|
|
49
|
-
// @ts-ignore
|
|
50
49
|
)
|
|
51
|
-
.on('error',
|
|
52
|
-
return
|
|
50
|
+
.on('error', err => this.emit('error', err))
|
|
51
|
+
return this
|
|
53
52
|
}
|
|
54
53
|
|
|
55
|
-
|
|
54
|
+
beforeETL (pipelineTask) {
|
|
56
55
|
const connectionname = pipelineTask.getConnectionName()
|
|
57
|
-
const connection = this.connectionList.
|
|
56
|
+
const connection = this.connectionList.find(c => c.name === connectionname)
|
|
58
57
|
if (!connection) {
|
|
59
58
|
throw new Error(`Connection with name ${connectionname} not found`)
|
|
60
59
|
}
|
|
61
60
|
pipelineTask.setConnection(connection)
|
|
62
|
-
pipelineTask.setETL(
|
|
63
|
-
|
|
64
|
-
return
|
|
61
|
+
pipelineTask.setETL(this)
|
|
62
|
+
this.beforeETLList.push(pipelineTask)
|
|
63
|
+
return this
|
|
65
64
|
}
|
|
66
65
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
return
|
|
66
|
+
connection (connection) {
|
|
67
|
+
this.connectionList.push(connection)
|
|
68
|
+
return this
|
|
70
69
|
}
|
|
71
70
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return
|
|
71
|
+
validator (validator) {
|
|
72
|
+
this.validatorList.push(validator)
|
|
73
|
+
return this
|
|
75
74
|
}
|
|
76
75
|
|
|
77
|
-
|
|
76
|
+
destination (destination, ...tasks) {
|
|
78
77
|
const connectionname = destination.getConnectionName()
|
|
79
|
-
const connection = this.connectionList.
|
|
78
|
+
const connection = this.connectionList.find(c => c.name === connectionname)
|
|
80
79
|
if (!connection && destination.type === 'PostgresDestination') {
|
|
81
80
|
throw new Error(`No connection could be found with name ${connectionname}`)
|
|
82
81
|
} else {
|
|
83
82
|
destination.setConnection(connection)
|
|
84
83
|
}
|
|
85
84
|
|
|
86
|
-
if (tasks) {
|
|
85
|
+
if (tasks && tasks.length > 0) {
|
|
87
86
|
for (const task of tasks) {
|
|
88
|
-
task.setETL(
|
|
87
|
+
task.setETL(this)
|
|
89
88
|
}
|
|
90
89
|
destination.setTasks(tasks)
|
|
91
90
|
}
|
|
92
|
-
|
|
93
|
-
return
|
|
91
|
+
this.destinationList.push(destination)
|
|
92
|
+
return this
|
|
94
93
|
}
|
|
95
94
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
return
|
|
95
|
+
transform (transform) {
|
|
96
|
+
this.transformationList.push(transform)
|
|
97
|
+
return this
|
|
99
98
|
}
|
|
100
99
|
}
|
|
101
100
|
|
|
102
|
-
util.inherits(Etl, EventEmitter)
|
|
103
|
-
|
|
104
101
|
module.exports = {
|
|
105
102
|
Etl
|
|
106
103
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
|
-
const { Transform } = require('stream')
|
|
2
|
+
const { Transform } = require('node:stream')
|
|
3
3
|
|
|
4
|
-
function
|
|
4
|
+
function rowMetaData () {
|
|
5
5
|
return new Transform({
|
|
6
6
|
readableObjectMode: true,
|
|
7
7
|
writableObjectMode: true,
|
|
@@ -20,5 +20,5 @@ function RowMetaData (options) {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
module.exports = {
|
|
23
|
-
RowMetaData
|
|
23
|
+
RowMetaData: rowMetaData
|
|
24
24
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
|
-
const fs = require('fs')
|
|
3
|
-
const { Transform } = require('stream')
|
|
2
|
+
const fs = require('node:fs')
|
|
3
|
+
const { Transform } = require('node:stream')
|
|
4
4
|
const { parse } = require('csv-parse')
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -12,18 +12,18 @@ const { parse } = require('csv-parse')
|
|
|
12
12
|
* @param {Boolean} [options.relax]
|
|
13
13
|
* @returns StreamReader
|
|
14
14
|
*/
|
|
15
|
-
function
|
|
16
|
-
let
|
|
15
|
+
function csvLoader (options) {
|
|
16
|
+
let loader
|
|
17
17
|
if (options.path) {
|
|
18
|
-
|
|
18
|
+
loader = fs.createReadStream(options.path)
|
|
19
19
|
} else {
|
|
20
|
-
|
|
20
|
+
loader = options.stream
|
|
21
21
|
}
|
|
22
22
|
let lineCount = 1
|
|
23
23
|
const fromLine = options.startingLine ?? 2
|
|
24
24
|
const relaxQuotes = options.relax ?? false
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
loader._columns = options.columns
|
|
26
|
+
loader.pump = () => {
|
|
27
27
|
const parser = parse({ delimiter: ',', from_line: fromLine, relax_quotes: relaxQuotes })
|
|
28
28
|
const transformer = new Transform({
|
|
29
29
|
readableObjectMode: true,
|
|
@@ -38,21 +38,21 @@ function CSVLoader (options) {
|
|
|
38
38
|
options.columns.forEach((_column, index) => {
|
|
39
39
|
if (chunk[index]) {
|
|
40
40
|
// eslint-disable-next-line no-control-regex
|
|
41
|
-
chunk[index] = chunk[index].
|
|
41
|
+
chunk[index] = chunk[index].replaceAll(/[\x00-\x1F\x7F-\x9F]/g, '')
|
|
42
42
|
}
|
|
43
43
|
})
|
|
44
44
|
|
|
45
45
|
callback(null, chunk)
|
|
46
46
|
}
|
|
47
47
|
})
|
|
48
|
-
return
|
|
48
|
+
return loader
|
|
49
49
|
.pipe(parser)
|
|
50
50
|
.pipe(transformer)
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
return
|
|
53
|
+
return loader
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
module.exports = {
|
|
57
|
-
CSVLoader
|
|
57
|
+
CSVLoader: csvLoader
|
|
58
58
|
}
|
package/app/loaders/index.js
CHANGED
package/app/misc/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
|
-
const { PassThrough } = require('stream')
|
|
2
|
+
const { PassThrough } = require('node:stream')
|
|
3
3
|
const startPosOffset = 3
|
|
4
4
|
const endPosOffset = 1
|
|
5
5
|
|
|
@@ -23,7 +23,7 @@ function doPlaceHolderValueInterpolations (chunk, sql, placeholders) {
|
|
|
23
23
|
return sql
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
function
|
|
26
|
+
function postgresSQLTask (options) {
|
|
27
27
|
const passthrough = new PassThrough({
|
|
28
28
|
readableObjectMode: true,
|
|
29
29
|
writableObjectMode: true,
|
|
@@ -39,17 +39,11 @@ function PostgresSQLTask (options) {
|
|
|
39
39
|
this.connection.db.query(this.sql)
|
|
40
40
|
} else {
|
|
41
41
|
const interpolatedSql = doPlaceHolderValueInterpolations(chunk, this.sql, placeholders)
|
|
42
|
-
// TODO add more interpolation mechanisms to specify return values
|
|
43
|
-
// e.g. 'myReturnVal = SELECT MAX ID FROM TABLE;'
|
|
44
|
-
// and write to etl.store.myReturnVal or
|
|
45
|
-
// e.g. 'chunk.myReturnVal = SELECT MAX ID FROM TABLE;'
|
|
46
|
-
// and write to the chunk in say chunk.store.myReturnVal
|
|
47
42
|
this.connection.db.query(interpolatedSql)
|
|
48
43
|
}
|
|
49
44
|
callback(null, chunk)
|
|
50
45
|
}
|
|
51
46
|
})
|
|
52
|
-
// Should definately split this out into a mixin
|
|
53
47
|
Object.assign(passthrough, {
|
|
54
48
|
setConnection: function (connection) {
|
|
55
49
|
this.connection = connection
|
|
@@ -65,7 +59,7 @@ function PostgresSQLTask (options) {
|
|
|
65
59
|
}
|
|
66
60
|
|
|
67
61
|
module.exports = {
|
|
68
|
-
PostgresSQLTask,
|
|
62
|
+
PostgresSQLTask: postgresSQLTask,
|
|
69
63
|
getPlaceHolders,
|
|
70
64
|
doPlaceHolderValueInterpolations
|
|
71
65
|
}
|
|
@@ -14,9 +14,8 @@ const { Transform } = require('node:stream')
|
|
|
14
14
|
* @param {String} options.locale
|
|
15
15
|
* @returns StreamReader
|
|
16
16
|
*/
|
|
17
|
-
function
|
|
18
|
-
const
|
|
19
|
-
self.columns = options.columns
|
|
17
|
+
function fakerTransformer (options) {
|
|
18
|
+
const columns = options.columns
|
|
20
19
|
let faker
|
|
21
20
|
if (options.locale) {
|
|
22
21
|
faker = require(`@faker-js/faker/locale/${options.locale}`).faker
|
|
@@ -29,12 +28,13 @@ function FakerTransformer (options) {
|
|
|
29
28
|
return Object.keys(a).length === 0 ? faker[b] : a[b]
|
|
30
29
|
}, {})
|
|
31
30
|
}
|
|
31
|
+
|
|
32
32
|
return new Transform({
|
|
33
33
|
readableObjectMode: true,
|
|
34
34
|
writableObjectMode: true,
|
|
35
35
|
transform (chunk, _, callback) {
|
|
36
36
|
const { _columns } = chunk
|
|
37
|
-
|
|
37
|
+
columns.forEach(column => {
|
|
38
38
|
const colIndex = _columns.indexOf(column.name)
|
|
39
39
|
chunk[colIndex] = getFaker(column.faker)()
|
|
40
40
|
})
|
|
@@ -44,5 +44,5 @@ function FakerTransformer (options) {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
module.exports = {
|
|
47
|
-
FakerTransformer
|
|
47
|
+
FakerTransformer: fakerTransformer
|
|
48
48
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const { ToUpperCaseTransformer } = require('./
|
|
2
|
-
const { FakerTransformer } = require('./
|
|
3
|
-
const { StringReplaceTransformer } = require('./
|
|
1
|
+
const { ToUpperCaseTransformer } = require('./to-upper-case-transformer')
|
|
2
|
+
const { FakerTransformer } = require('./faker-transformer')
|
|
3
|
+
const { StringReplaceTransformer } = require('./string-replace-transformer')
|
|
4
4
|
|
|
5
5
|
module.exports = {
|
|
6
6
|
StringReplaceTransformer,
|
|
@@ -6,9 +6,8 @@ const { Transform } = require('node:stream')
|
|
|
6
6
|
* @param {String} options.column
|
|
7
7
|
* @returns Writable
|
|
8
8
|
*/
|
|
9
|
-
function
|
|
10
|
-
const
|
|
11
|
-
self.replacements = options
|
|
9
|
+
function stringReplaceTransformer (options) {
|
|
10
|
+
const replacements = options
|
|
12
11
|
|
|
13
12
|
return new Transform({
|
|
14
13
|
readableObjectMode: true,
|
|
@@ -16,8 +15,12 @@ function StringReplaceTransformer (options) {
|
|
|
16
15
|
transform (chunk, _, callback) {
|
|
17
16
|
const { _columns } = chunk
|
|
18
17
|
// @ts-ignore
|
|
19
|
-
|
|
18
|
+
replacements.forEach(r => {
|
|
20
19
|
const colIndex = _columns.indexOf(r.column)
|
|
20
|
+
if (colIndex === -1) {
|
|
21
|
+
// column not found, skip
|
|
22
|
+
return
|
|
23
|
+
}
|
|
21
24
|
if (r.all) {
|
|
22
25
|
chunk[colIndex] = chunk[colIndex].replaceAll(r.find, r.replace)
|
|
23
26
|
} else {
|
|
@@ -31,5 +34,5 @@ function StringReplaceTransformer (options) {
|
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
module.exports = {
|
|
34
|
-
StringReplaceTransformer
|
|
37
|
+
StringReplaceTransformer: stringReplaceTransformer
|
|
35
38
|
}
|
|
@@ -6,22 +6,24 @@ const { Transform } = require('node:stream')
|
|
|
6
6
|
* @param {String} options.column
|
|
7
7
|
* @returns Writable
|
|
8
8
|
*/
|
|
9
|
-
function
|
|
10
|
-
const
|
|
11
|
-
self.column = options.column
|
|
9
|
+
function toUpperCaseTransformer (options) {
|
|
10
|
+
const column = options.column
|
|
12
11
|
|
|
13
12
|
return new Transform({
|
|
14
13
|
readableObjectMode: true,
|
|
15
14
|
writableObjectMode: true,
|
|
16
15
|
transform (chunk, _, callback) {
|
|
17
16
|
const { _columns } = chunk
|
|
18
|
-
const colIndex = _columns.indexOf(
|
|
19
|
-
|
|
17
|
+
const colIndex = _columns.indexOf(column)
|
|
18
|
+
|
|
19
|
+
if (colIndex !== -1 && chunk[colIndex] != null) {
|
|
20
|
+
chunk[colIndex] = chunk[colIndex].toUpperCase()
|
|
21
|
+
}
|
|
20
22
|
callback(null, chunk)
|
|
21
23
|
}
|
|
22
24
|
})
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
module.exports = {
|
|
26
|
-
ToUpperCaseTransformer
|
|
28
|
+
ToUpperCaseTransformer: toUpperCaseTransformer
|
|
27
29
|
}
|