ffc-pay-etl-framework 0.0.10 → 0.0.11

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
@@ -1,15 +1,20 @@
1
1
  ## 🚀 Features
2
+
2
3
  <!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
4
+
3
5
  [![All Contributors](https://img.shields.io/badge/all_contributors-2-orange.svg?style=flat-square)](#contributors-)
6
+
4
7
  <!-- ALL-CONTRIBUTORS-BADGE:END -->
8
+
5
9
  - 💾 CSV Source and Destination
6
10
  - 👮 Validators
7
11
  - 🤖 Transformers
8
12
  - 🚨 Error Checking
9
13
  - 🐘 Write directly to Postgres
10
- - 👨‍⚕️ Intellisense
14
+ - 👨‍⚕️ Intellisense
11
15
 
12
16
  ## 📦 Install
17
+
13
18
  ```bash
14
19
  npm install --save-dev ffc-pay-etl-framework
15
20
  ```
@@ -18,30 +23,56 @@ npm install --save-dev ffc-pay-etl-framework
18
23
 
19
24
  ```js
20
25
  // ESM
21
- import { Etl, Loaders, Validators, Transformers, Destinations } from "ffc-pay-etl-framework"
26
+ import {
27
+ Etl,
28
+ Loaders,
29
+ Validators,
30
+ Transformers,
31
+ Destinations,
32
+ } from "ffc-pay-etl-framework";
22
33
 
23
34
  // CJS
24
- const { Etl, Loaders, Validators, Transformers, Destinations } = require("ffc-pay-etl-framework")
35
+ const {
36
+ Etl,
37
+ Loaders,
38
+ Validators,
39
+ Transformers,
40
+ Destinations,
41
+ } = require("ffc-pay-etl-framework");
25
42
 
26
- let csvFile = `${process.cwd()}/test/fixtures/SoilType.csv`
43
+ let csvFile = `${process.cwd()}/test/fixtures/SoilType.csv`;
44
+ const spinner = new pkg.Spinner().start("Running ETL Pipeline");
27
45
 
28
- const etl = new Etl.Etl()
46
+ const etl = new Etl.Etl();
29
47
 
30
48
  etl
31
- .loader(Loaders.CSVLoader({path: csvFile, columns: columns}))
32
- .transform(Transformers.FakerTransformer({
33
- columns: [{
34
- name: "Dist Name",
35
- faker: "location.city"
36
- }]
37
- }))
38
- .destination(Destinations.CSVFileDestination({
39
- fileName: "SoilType_Output.csv",
40
- headers: true,
41
- includeErrors: false,
42
- quotationMarks: true
43
- }))
44
- .pump()
49
+ .loader(Loaders.CSVLoader({ path: csvFile, columns: columns }))
50
+ .transform(
51
+ Transformers.FakerTransformer({
52
+ columns: [
53
+ {
54
+ name: "Dist Name",
55
+ faker: "location.city",
56
+ },
57
+ ],
58
+ })
59
+ )
60
+ .destination(
61
+ Destinations.CSVFileDestination({
62
+ fileName: "SoilType_Output.csv",
63
+ headers: true,
64
+ includeErrors: false,
65
+ quotationMarks: true,
66
+ })
67
+ )
68
+ .pump()
69
+ .on("finish", () => {
70
+ //Update spinner
71
+ spinner.succeed("ETL Pipeline - succeeded");
72
+ })
73
+ .on("result", (data) => {
74
+ console.log(data); // emits the last row with error information
75
+ });
45
76
  ```
46
77
 
47
78
  ## 📢 Shout outs
@@ -56,7 +87,6 @@ etl
56
87
 
57
88
  Please make sure to read the [Contributing Guide](https://github.com/DEFRA/ffc-pay-etl-framework/blob/next/CONTRIBUTING.md) before making a pull request.
58
89
 
59
-
60
90
  ## Contributors ✨
61
91
 
62
92
  Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
@@ -87,4 +117,4 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
87
117
 
88
118
  <!-- ALL-CONTRIBUTORS-LIST:END -->
89
119
 
90
- This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
120
+ This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
@@ -1,3 +1,5 @@
1
+ const EventEmitter = require('node:events');
2
+ const util = require('node:util');
1
3
  const { Writable } = require("node:stream");
2
4
  const fs = require("fs");
3
5
  /**
@@ -10,6 +12,8 @@ const fs = require("fs");
10
12
  * @returns Writable
11
13
  */
12
14
  function CSVFileDestination(options) {
15
+ EventEmitter.call(this);
16
+ let lastChunk;
13
17
  const fileName = options.fileName;
14
18
  const headers = options.headers;
15
19
  const includeErrors = options.includeErrors;
@@ -39,10 +43,16 @@ function CSVFileDestination(options) {
39
43
  fs.writeFileSync(fileHandle, `${chunk.map(c => `"${c}"`).join(",")}\n`);
40
44
  }
41
45
  }
46
+ lastChunk = chunk;
47
+ callback();
48
+ },
49
+ final(callback) {
50
+ this.emit('result', lastChunk);
42
51
  callback();
43
52
  }
44
53
  });
45
54
  }
55
+ util.inherits(CSVFileDestination, EventEmitter);
46
56
  module.exports = {
47
57
  CSVFileDestination
48
58
  };
@@ -1,3 +1,5 @@
1
+ const EventEmitter = require('node:events');
2
+ const util = require('node:util');
1
3
  const { Transform } = require('node:stream');
2
4
  const { Sequelize } = require('sequelize');
3
5
  const debug = require('debug')('destination');
@@ -16,6 +18,7 @@ const DEFAULT_PORT = 5432;
16
18
  * @returns Transform
17
19
  */
18
20
  function PostgresDestination(options) {
21
+ EventEmitter.call(this);
19
22
  const table = options.table;
20
23
  const username = options.username;
21
24
  const password = options.password;
@@ -24,6 +27,7 @@ function PostgresDestination(options) {
24
27
  const port = options.port || DEFAULT_PORT;
25
28
  const mapping = options.mapping;
26
29
  const includeErrors = options.includeErrors;
30
+ let lastChunk;
27
31
  const sequelize = new Sequelize(database, username, password, {
28
32
  host: host,
29
33
  port: port,
@@ -91,11 +95,13 @@ function PostgresDestination(options) {
91
95
  .then(result => {
92
96
  debug('result %o', result);
93
97
  chunk._result = result;
98
+ lastChunk = chunk;
94
99
  // @ts-ignore
95
100
  callback(null, chunk);
96
101
  }).catch(error => {
97
102
  debug('error %o', error);
98
103
  chunk.errors.push(error);
104
+ lastChunk = chunk;
99
105
  // @ts-ignore
100
106
  callback(null, chunk);
101
107
  });
@@ -103,6 +109,10 @@ function PostgresDestination(options) {
103
109
  else {
104
110
  debug('Chunk has errors %o', chunk);
105
111
  }
112
+ },
113
+ final(callback) {
114
+ this.emit('result', lastChunk);
115
+ callback();
106
116
  }
107
117
  });
108
118
  }
@@ -28,7 +28,7 @@ function Etl() {
28
28
  this.pump = () => {
29
29
  this.loader
30
30
  .pump(this.loader)
31
- .pipe(compose(RowMetaData(), ...self.validatorList, ...self.transformationList, ...self.destinationList)
31
+ .pipe(compose(RowMetaData(), ...self.validatorList, ...self.transformationList, ...self.destinationList.map(dl => dl.on('result', (data) => self.emit('result', data))))
32
32
  // @ts-ignore
33
33
  ).on('finish', (data) => self.emit('finish', data));
34
34
  return self;
@@ -2,7 +2,7 @@
2
2
  const fs = require("fs");
3
3
  const { Transform } = require("stream");
4
4
  const { parse } = require("csv-parse");
5
- const { stdout } = require("process");
5
+ const { stdout, stderr } = require("process");
6
6
  /**
7
7
  *
8
8
  * @param {Object} options
@@ -11,6 +11,7 @@ const { stdout } = require("process");
11
11
  */
12
12
  function CSVLoader(options) {
13
13
  let csvLoader = fs.createReadStream(options.path);
14
+ let lineCount = 1;
14
15
  csvLoader._columns = options.columns;
15
16
  csvLoader.pump = (csvLoader) => {
16
17
  return csvLoader
@@ -21,6 +22,8 @@ function CSVLoader(options) {
21
22
  emitClose: true,
22
23
  transform(chunk, _, callback) {
23
24
  chunk["_columns"] = options.columns;
25
+ chunk["_linecount"] = lineCount;
26
+ lineCount += 1;
24
27
  callback(null, chunk);
25
28
  }
26
29
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"csvFileDestination.d.ts","sourceRoot":"","sources":["../../../../src/destinations/csvFileDestination.js"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,4CANG;IAAwB,QAAQ;IACP,OAAO;IACP,aAAa;IACb,cAAc;CACvC,YAkCF"}
1
+ {"version":3,"file":"csvFileDestination.d.ts","sourceRoot":"","sources":["../../../../src/destinations/csvFileDestination.js"],"names":[],"mappings":"AAKA;;;;;;;;GAQG;AACH,4CANG;IAAwB,QAAQ;IACP,OAAO;IACP,aAAa;IACb,cAAc;CACvC,YAwCF"}
@@ -1 +1 @@
1
- {"version":3,"file":"postgresDestination.d.ts","sourceRoot":"","sources":["../../../../src/destinations/postgresDestination.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AACH,6CAVG;IAAwB,KAAK;IACL,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,IAAI;IACJ,IAAI;IACJ,OAAO;IACP,aAAa;CACrC,aA6FF"}
1
+ {"version":3,"file":"postgresDestination.d.ts","sourceRoot":"","sources":["../../../../src/destinations/postgresDestination.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;GAYG;AACH,6CAVG;IAAwB,KAAK;IACL,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,IAAI;IACJ,IAAI;IACJ,OAAO;IACP,aAAa;CACrC,aAoGF"}
@@ -1 +1 @@
1
- {"version":3,"file":"csvloader.d.ts","sourceRoot":"","sources":["../../../../src/loaders/csvloader.js"],"names":[],"mappings":"AAMA;;;;;GAKG;AACH,mCAHG;IAAwB,IAAI;CAC5B,iBAoBF"}
1
+ {"version":3,"file":"csvloader.d.ts","sourceRoot":"","sources":["../../../../src/loaders/csvloader.js"],"names":[],"mappings":"AAMA;;;;;GAKG;AACH,mCAHG;IAAwB,IAAI;CAC5B,iBAuBF"}
@@ -1,4 +1,6 @@
1
1
  "use strict";
2
+ const EventEmitter = require('node:events');
3
+ const util = require('node:util');
2
4
  const { Writable } = require("node:stream");
3
5
  const fs = require("fs");
4
6
  /**
@@ -11,6 +13,8 @@ const fs = require("fs");
11
13
  * @returns Writable
12
14
  */
13
15
  function CSVFileDestination(options) {
16
+ EventEmitter.call(this);
17
+ let lastChunk;
14
18
  const fileName = options.fileName;
15
19
  const headers = options.headers;
16
20
  const includeErrors = options.includeErrors;
@@ -40,10 +44,16 @@ function CSVFileDestination(options) {
40
44
  fs.writeFileSync(fileHandle, `${chunk.map(c => `"${c}"`).join(",")}\n`);
41
45
  }
42
46
  }
47
+ lastChunk = chunk;
48
+ callback();
49
+ },
50
+ final(callback) {
51
+ this.emit('result', lastChunk);
43
52
  callback();
44
53
  }
45
54
  });
46
55
  }
56
+ util.inherits(CSVFileDestination, EventEmitter);
47
57
  module.exports = {
48
58
  CSVFileDestination
49
59
  };
@@ -1,4 +1,6 @@
1
1
  "use strict";
2
+ const EventEmitter = require('node:events');
3
+ const util = require('node:util');
2
4
  const { Transform } = require('node:stream');
3
5
  const { Sequelize } = require('sequelize');
4
6
  const debug = require('debug')('destination');
@@ -17,6 +19,7 @@ const DEFAULT_PORT = 5432;
17
19
  * @returns Transform
18
20
  */
19
21
  function PostgresDestination(options) {
22
+ EventEmitter.call(this);
20
23
  const table = options.table;
21
24
  const username = options.username;
22
25
  const password = options.password;
@@ -25,6 +28,7 @@ function PostgresDestination(options) {
25
28
  const port = options.port || DEFAULT_PORT;
26
29
  const mapping = options.mapping;
27
30
  const includeErrors = options.includeErrors;
31
+ let lastChunk;
28
32
  const sequelize = new Sequelize(database, username, password, {
29
33
  host: host,
30
34
  port: port,
@@ -92,11 +96,13 @@ function PostgresDestination(options) {
92
96
  .then(result => {
93
97
  debug('result %o', result);
94
98
  chunk._result = result;
99
+ lastChunk = chunk;
95
100
  // @ts-ignore
96
101
  callback(null, chunk);
97
102
  }).catch(error => {
98
103
  debug('error %o', error);
99
104
  chunk.errors.push(error);
105
+ lastChunk = chunk;
100
106
  // @ts-ignore
101
107
  callback(null, chunk);
102
108
  });
@@ -104,6 +110,10 @@ function PostgresDestination(options) {
104
110
  else {
105
111
  debug('Chunk has errors %o', chunk);
106
112
  }
113
+ },
114
+ final(callback) {
115
+ this.emit('result', lastChunk);
116
+ callback();
107
117
  }
108
118
  });
109
119
  }
@@ -29,7 +29,7 @@ function Etl() {
29
29
  this.pump = () => {
30
30
  this.loader
31
31
  .pump(this.loader)
32
- .pipe(compose(RowMetaData(), ...self.validatorList, ...self.transformationList, ...self.destinationList)
32
+ .pipe(compose(RowMetaData(), ...self.validatorList, ...self.transformationList, ...self.destinationList.map(dl => dl.on('result', (data) => self.emit('result', data))))
33
33
  // @ts-ignore
34
34
  ).on('finish', (data) => self.emit('finish', data));
35
35
  return self;
@@ -3,7 +3,7 @@
3
3
  const fs = require("fs");
4
4
  const { Transform } = require("stream");
5
5
  const { parse } = require("csv-parse");
6
- const { stdout } = require("process");
6
+ const { stdout, stderr } = require("process");
7
7
  /**
8
8
  *
9
9
  * @param {Object} options
@@ -12,6 +12,7 @@ const { stdout } = require("process");
12
12
  */
13
13
  function CSVLoader(options) {
14
14
  let csvLoader = fs.createReadStream(options.path);
15
+ let lineCount = 1;
15
16
  csvLoader._columns = options.columns;
16
17
  csvLoader.pump = (csvLoader) => {
17
18
  return csvLoader
@@ -22,6 +23,8 @@ function CSVLoader(options) {
22
23
  emitClose: true,
23
24
  transform(chunk, _, callback) {
24
25
  chunk["_columns"] = options.columns;
26
+ chunk["_linecount"] = lineCount;
27
+ lineCount += 1;
25
28
  callback(null, chunk);
26
29
  }
27
30
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"csvFileDestination.d.ts","sourceRoot":"","sources":["../../../../src/destinations/csvFileDestination.js"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,4CANG;IAAwB,QAAQ;IACP,OAAO;IACP,aAAa;IACb,cAAc;CACvC,YAkCF"}
1
+ {"version":3,"file":"csvFileDestination.d.ts","sourceRoot":"","sources":["../../../../src/destinations/csvFileDestination.js"],"names":[],"mappings":"AAKA;;;;;;;;GAQG;AACH,4CANG;IAAwB,QAAQ;IACP,OAAO;IACP,aAAa;IACb,cAAc;CACvC,YAwCF"}
@@ -1 +1 @@
1
- {"version":3,"file":"postgresDestination.d.ts","sourceRoot":"","sources":["../../../../src/destinations/postgresDestination.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AACH,6CAVG;IAAwB,KAAK;IACL,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,IAAI;IACJ,IAAI;IACJ,OAAO;IACP,aAAa;CACrC,aA6FF"}
1
+ {"version":3,"file":"postgresDestination.d.ts","sourceRoot":"","sources":["../../../../src/destinations/postgresDestination.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;GAYG;AACH,6CAVG;IAAwB,KAAK;IACL,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,IAAI;IACJ,IAAI;IACJ,OAAO;IACP,aAAa;CACrC,aAoGF"}
@@ -1 +1 @@
1
- {"version":3,"file":"csvloader.d.ts","sourceRoot":"","sources":["../../../../src/loaders/csvloader.js"],"names":[],"mappings":"AAMA;;;;;GAKG;AACH,mCAHG;IAAwB,IAAI;CAC5B,iBAoBF"}
1
+ {"version":3,"file":"csvloader.d.ts","sourceRoot":"","sources":["../../../../src/loaders/csvloader.js"],"names":[],"mappings":"AAMA;;;;;GAKG;AACH,mCAHG;IAAwB,IAAI;CAC5B,iBAuBF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ffc-pay-etl-framework",
3
- "version": "0.0.10",
3
+ "version": "0.0.11",
4
4
  "publisher": "Defra",
5
5
  "main": "dist/cjs/index.js",
6
6
  "private": false,