@restorecommerce/gql-bot 0.1.11 → 0.1.16
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/CHANGELOG.md +53 -0
- package/LICENSE +2 -2
- package/lib/client.d.ts +9 -0
- package/lib/client.js +150 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.js +10 -0
- package/lib/job_processor.d.ts +21 -0
- package/lib/job_processor.js +153 -0
- package/lib/job_processor_gql.d.ts +10 -0
- package/lib/job_processor_gql.js +109 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,59 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [0.1.16](https://github.com/restorecommerce/libs/compare/@restorecommerce/gql-bot@0.1.15...@restorecommerce/gql-bot@0.1.16) (2022-02-14)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @restorecommerce/gql-bot
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [0.1.15](https://github.com/restorecommerce/libs/compare/@restorecommerce/gql-bot@0.1.14...@restorecommerce/gql-bot@0.1.15) (2021-08-23)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Bug Fixes
|
|
18
|
+
|
|
19
|
+
* **version:** up version to be in sync in package-lock ([b8f22c1](https://github.com/restorecommerce/libs/commit/b8f22c1268ee2af4beff7d88bda30f197896e3d2))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
## [0.1.14](https://github.com/restorecommerce/libs/compare/@restorecommerce/gql-bot@0.1.13...@restorecommerce/gql-bot@0.1.14) (2021-08-10)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
### Bug Fixes
|
|
29
|
+
|
|
30
|
+
* **acs-client, gql-bot, kafka-client, koa-health-check:** eslintrc added root to uniquely identify eslint plugin package to avoid error building facade-srv ([c2e446b](https://github.com/restorecommerce/libs/commit/c2e446bf0f09d7fa4f000da3bb09fd612cb9526c))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
## [0.1.13](https://github.com/restorecommerce/libs/compare/@restorecommerce/gql-bot@0.1.12...@restorecommerce/gql-bot@0.1.13) (2021-08-03)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
### Bug Fixes
|
|
40
|
+
|
|
41
|
+
* up pkg locks ([8ed92d6](https://github.com/restorecommerce/libs/commit/8ed92d613b9a095e4b5066056ac566e5dbcf1472))
|
|
42
|
+
* updated githead ([2904d30](https://github.com/restorecommerce/libs/commit/2904d30e5773dc8a87c01a08ff6481f99d692354))
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
## [0.1.12](https://github.com/restorecommerce/libs/compare/@restorecommerce/gql-bot@0.1.11...@restorecommerce/gql-bot@0.1.12) (2021-08-03)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
### Bug Fixes
|
|
52
|
+
|
|
53
|
+
* **koa-health-check:** added missing .eslintrc.js ([45af632](https://github.com/restorecommerce/libs/commit/45af632955d2dd448e7a27f4e8c4b971412cd004))
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
6
59
|
## [0.1.11](https://github.com/restorecommerce/libs/compare/@restorecommerce/gql-bot@0.1.10...@restorecommerce/gql-bot@0.1.11) (2021-06-26)
|
|
7
60
|
|
|
8
61
|
**Note:** Version bump only for package @restorecommerce/gql-bot
|
package/LICENSE
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Copyright (c)
|
|
1
|
+
Copyright (c) n-fuse GmbH and other contributors.
|
|
2
2
|
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
4
4
|
this software and associated documentation files (the "Software"), to deal in
|
|
@@ -16,4 +16,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
16
16
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
17
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
18
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
-
SOFTWARE.
|
|
19
|
+
SOFTWARE.
|
package/lib/client.d.ts
ADDED
package/lib/client.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.Client = void 0;
|
|
13
|
+
const _ = require("lodash");
|
|
14
|
+
const url = require("url");
|
|
15
|
+
const fs = require("fs");
|
|
16
|
+
const graphql_tag_1 = require("graphql-tag");
|
|
17
|
+
const apollo_client_1 = require("apollo-client");
|
|
18
|
+
const apollo_cache_inmemory_1 = require("apollo-cache-inmemory");
|
|
19
|
+
const node_fetch_1 = require("node-fetch"); // required for apollo-link-http
|
|
20
|
+
const apollo_link_http_1 = require("apollo-link-http");
|
|
21
|
+
function _checkVariableMutation(mutation) {
|
|
22
|
+
const mutationName = mutation.slice(mutation.indexOf(' '), mutation.indexOf('($'));
|
|
23
|
+
if (mutationName.indexOf('$') > 0) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
return new RegExp('\\b' + mutationName + '\\(', 'i').test(mutation);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function _replaceInlineVars(mutation, args) {
|
|
31
|
+
if (mutation)
|
|
32
|
+
return mutation.replace(/\${(\w+)}/g, (_, v) => args[v]);
|
|
33
|
+
}
|
|
34
|
+
function _createQueryVariables(inputVarName, queryVarKey, varValue) {
|
|
35
|
+
if (queryVarKey) {
|
|
36
|
+
return {
|
|
37
|
+
[inputVarName]: {
|
|
38
|
+
[queryVarKey]: JSON.parse(varValue)
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
[inputVarName]: JSON.parse(varValue)
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
class Client {
|
|
47
|
+
constructor(opts) {
|
|
48
|
+
if (_.isNil(opts)) {
|
|
49
|
+
throw new Error('Missing options parameter');
|
|
50
|
+
}
|
|
51
|
+
this.metaQs = { meta: true };
|
|
52
|
+
_.defaults(opts, {
|
|
53
|
+
entry: null,
|
|
54
|
+
protocol: 'http',
|
|
55
|
+
apiKey: null,
|
|
56
|
+
headers: {}
|
|
57
|
+
});
|
|
58
|
+
const required = ['entry'];
|
|
59
|
+
required.forEach((key) => {
|
|
60
|
+
if (!opts[key]) {
|
|
61
|
+
throw new Error('Missing option: \'' + key + '\'');
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
this.opts = opts;
|
|
65
|
+
this._buildURLs();
|
|
66
|
+
_.assign(this.opts.headers, {
|
|
67
|
+
Accept: 'application/json',
|
|
68
|
+
Origin: this.entryBaseUrl
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
_buildURLs() {
|
|
72
|
+
const entry = this.opts.entry;
|
|
73
|
+
if (!String(entry).startsWith('http')) {
|
|
74
|
+
this.opts.entry = this.opts.protocol + '://' + entry;
|
|
75
|
+
}
|
|
76
|
+
const parsedEntry = url.parse(entry);
|
|
77
|
+
if (parsedEntry.protocol) {
|
|
78
|
+
this.opts.protocol = parsedEntry.protocol;
|
|
79
|
+
}
|
|
80
|
+
const protocol = this.opts.protocol + '//';
|
|
81
|
+
this.entryBaseUrl = protocol + parsedEntry.host + parsedEntry.path;
|
|
82
|
+
}
|
|
83
|
+
_normalizeUrl(source) {
|
|
84
|
+
let extendURL = '';
|
|
85
|
+
if (source) {
|
|
86
|
+
// this is source.path /restore/oss-client/test/folder/file.1
|
|
87
|
+
if (!source.path && source != true) {
|
|
88
|
+
extendURL = source;
|
|
89
|
+
}
|
|
90
|
+
if (source.path) {
|
|
91
|
+
// TODO: read this 'the Node way'
|
|
92
|
+
extendURL = fs.readFileSync(source.path).toString();
|
|
93
|
+
extendURL = '?query=' + extendURL;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return url.resolve(this.entryBaseUrl, extendURL);
|
|
97
|
+
}
|
|
98
|
+
post(source, job, accessControl, formOptions) {
|
|
99
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
100
|
+
const normalUrl = this._normalizeUrl();
|
|
101
|
+
let mutation;
|
|
102
|
+
if (job && job.mutation) {
|
|
103
|
+
mutation = JSON.stringify(job.mutation);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
throw new Error('mutation not present in job config');
|
|
107
|
+
}
|
|
108
|
+
const apiKey = JSON.stringify(this.opts.apiKey);
|
|
109
|
+
let resource_list = JSON.stringify(source);
|
|
110
|
+
if (mutation) {
|
|
111
|
+
// don't replace quoted strings inside outer quotes
|
|
112
|
+
// (i.e. if the quote is preceded by a backslash)
|
|
113
|
+
// make sure to also match line/expression start
|
|
114
|
+
// and keep the symbol preceding the quote
|
|
115
|
+
mutation = mutation.replace(/(^|[^\\])\"/g, '$1');
|
|
116
|
+
// afterwards, replace escaped quotes with regular ones
|
|
117
|
+
mutation = mutation.replace(/\\\"/g, '\"');
|
|
118
|
+
}
|
|
119
|
+
let variables;
|
|
120
|
+
if (_checkVariableMutation(mutation)) {
|
|
121
|
+
const queryVarKey = job.queryVariables;
|
|
122
|
+
const inputVarName = mutation.slice(mutation.indexOf('$') + 1, mutation.indexOf(':'));
|
|
123
|
+
variables = _createQueryVariables(inputVarName, queryVarKey, resource_list);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
// To remove double quotes from the keys in JSON data
|
|
127
|
+
resource_list = resource_list.replace(/\"([^(\")"]+)\":/g, '$1:');
|
|
128
|
+
mutation = _replaceInlineVars(mutation, { resource_list, apiKey });
|
|
129
|
+
}
|
|
130
|
+
const apolloLinkOpts = {
|
|
131
|
+
uri: normalUrl,
|
|
132
|
+
fetch: node_fetch_1.default
|
|
133
|
+
};
|
|
134
|
+
if (this.opts.headers) {
|
|
135
|
+
apolloLinkOpts['headers'] = this.opts.headers;
|
|
136
|
+
}
|
|
137
|
+
let apolloLink = apollo_link_http_1.createHttpLink(apolloLinkOpts);
|
|
138
|
+
const apolloCache = new apollo_cache_inmemory_1.InMemoryCache();
|
|
139
|
+
const apolloClient = new apollo_client_1.ApolloClient({
|
|
140
|
+
cache: apolloCache,
|
|
141
|
+
link: apolloLink
|
|
142
|
+
});
|
|
143
|
+
return apolloClient.mutate({
|
|
144
|
+
mutation: graphql_tag_1.default `${mutation}`,
|
|
145
|
+
variables
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
exports.Client = Client;
|
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Job = exports.JobProcessor = exports.GraphQLProcessor = exports.Client = void 0;
|
|
4
|
+
const client_1 = require("./client");
|
|
5
|
+
Object.defineProperty(exports, "Client", { enumerable: true, get: function () { return client_1.Client; } });
|
|
6
|
+
const job_processor_gql_1 = require("./job_processor_gql");
|
|
7
|
+
Object.defineProperty(exports, "GraphQLProcessor", { enumerable: true, get: function () { return job_processor_gql_1.GraphQLProcessor; } });
|
|
8
|
+
const job_processor_1 = require("./job_processor");
|
|
9
|
+
Object.defineProperty(exports, "JobProcessor", { enumerable: true, get: function () { return job_processor_1.JobProcessor; } });
|
|
10
|
+
Object.defineProperty(exports, "Job", { enumerable: true, get: function () { return job_processor_1.Job; } });
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { Readable } from 'stream';
|
|
3
|
+
import { EventEmitter } from 'events';
|
|
4
|
+
export declare class ReadArrayStream extends Readable {
|
|
5
|
+
array: any[];
|
|
6
|
+
constructor(opts: any, array: any[]);
|
|
7
|
+
_read(): void;
|
|
8
|
+
}
|
|
9
|
+
export declare class Job extends EventEmitter {
|
|
10
|
+
opts: any;
|
|
11
|
+
constructor(opts?: any);
|
|
12
|
+
}
|
|
13
|
+
export declare class JobProcessor {
|
|
14
|
+
jobInfo: any;
|
|
15
|
+
processed: number;
|
|
16
|
+
processedTasks: number;
|
|
17
|
+
taskStream: any;
|
|
18
|
+
constructor(jobInfo: any);
|
|
19
|
+
start(tasks?: any, job?: Job): Promise<any>;
|
|
20
|
+
sync(task: any, job: Job): Promise<any>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.JobProcessor = exports.Job = exports.ReadArrayStream = void 0;
|
|
13
|
+
const _ = require("lodash");
|
|
14
|
+
const ps = require("promise-streams");
|
|
15
|
+
const stream_1 = require("stream");
|
|
16
|
+
const through2 = require("through2");
|
|
17
|
+
const readdirp = require("readdirp");
|
|
18
|
+
const path = require("path");
|
|
19
|
+
const events_1 = require("events");
|
|
20
|
+
class ReadArrayStream extends stream_1.Readable {
|
|
21
|
+
constructor(opts, array) {
|
|
22
|
+
super(opts);
|
|
23
|
+
this.array = _.clone(array);
|
|
24
|
+
}
|
|
25
|
+
_read() {
|
|
26
|
+
if (this.array && this.array.length > 0) {
|
|
27
|
+
const data = this.array.shift();
|
|
28
|
+
this.push(data);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
this.push(null);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.ReadArrayStream = ReadArrayStream;
|
|
36
|
+
/*
|
|
37
|
+
* A class to represent a job and its end result as promise.
|
|
38
|
+
* It also reports the progress as event emitter.
|
|
39
|
+
*/
|
|
40
|
+
class Job extends events_1.EventEmitter {
|
|
41
|
+
constructor(opts) {
|
|
42
|
+
super();
|
|
43
|
+
this.setMaxListeners(100);
|
|
44
|
+
this.opts = opts || {};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.Job = Job;
|
|
48
|
+
class JobProcessor {
|
|
49
|
+
constructor(jobInfo) {
|
|
50
|
+
this.jobInfo = jobInfo;
|
|
51
|
+
this.processed = 0;
|
|
52
|
+
_.defaults(this.jobInfo, {
|
|
53
|
+
concurrency: 3,
|
|
54
|
+
processor: null
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
start(tasks, job) {
|
|
58
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
59
|
+
job = job || new Job();
|
|
60
|
+
tasks = tasks || this.jobInfo.tasks;
|
|
61
|
+
const concurrency = this.jobInfo.options.concurrency;
|
|
62
|
+
this.taskStream = ps.map({ concurrent: concurrency }, (task) => {
|
|
63
|
+
return this.jobInfo.options.processor.process(task).then((body) => {
|
|
64
|
+
console.log('Processed task [' + this.processed + '] and status is:' + JSON.stringify(body));
|
|
65
|
+
this.processed++;
|
|
66
|
+
task.inputTask.processing--;
|
|
67
|
+
task.progress.value = 100; // task complete
|
|
68
|
+
job.emit('progress', task);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
this.taskStream.setMaxListeners(100);
|
|
72
|
+
const inputTaskStream = new ReadArrayStream({
|
|
73
|
+
objectMode: true
|
|
74
|
+
}, tasks);
|
|
75
|
+
inputTaskStream.pipe(through2.obj((task, enc, cb) => __awaiter(this, void 0, void 0, function* () {
|
|
76
|
+
const operation = task.operation;
|
|
77
|
+
yield this[operation].apply(this, [task, job]);
|
|
78
|
+
cb();
|
|
79
|
+
})));
|
|
80
|
+
yield ps.wait(inputTaskStream);
|
|
81
|
+
this.taskStream.on('error', (err) => { throw err; });
|
|
82
|
+
this.taskStream.on('end', () => {
|
|
83
|
+
// console.log('Stream ended');
|
|
84
|
+
});
|
|
85
|
+
const tasksStreamEnded = ps.wait(this.taskStream);
|
|
86
|
+
// Wait until the task stream emitted 'end'
|
|
87
|
+
tasksStreamEnded.then(() => {
|
|
88
|
+
job.emit('done');
|
|
89
|
+
});
|
|
90
|
+
return job;
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
sync(task, job) {
|
|
94
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
95
|
+
const pathOptions = {
|
|
96
|
+
fileFilter: (entry) => { return true; },
|
|
97
|
+
depth: 1,
|
|
98
|
+
lstat: true
|
|
99
|
+
};
|
|
100
|
+
const pathSegments = [process.cwd()];
|
|
101
|
+
if (!_.isUndefined(this.jobInfo.base)) {
|
|
102
|
+
pathSegments.push(this.jobInfo.base);
|
|
103
|
+
}
|
|
104
|
+
if (!_.isUndefined(task.src)) {
|
|
105
|
+
pathSegments.push(task.src);
|
|
106
|
+
}
|
|
107
|
+
pathOptions.fileFilter = task.filter || pathOptions.fileFilter;
|
|
108
|
+
if (task.depth) {
|
|
109
|
+
pathOptions.depth = task.depth;
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
delete pathOptions.depth;
|
|
113
|
+
}
|
|
114
|
+
const fileItemStream = readdirp(path.join.apply(this, pathSegments), pathOptions);
|
|
115
|
+
yield new Promise((resolve, reject) => {
|
|
116
|
+
fileItemStream
|
|
117
|
+
.on('warn', (warn) => {
|
|
118
|
+
job.emit('warn', warn);
|
|
119
|
+
})
|
|
120
|
+
.on('error', (err) => {
|
|
121
|
+
job.emit('error', err);
|
|
122
|
+
})
|
|
123
|
+
.on('data', (fileItem) => {
|
|
124
|
+
fileItem.progress = {
|
|
125
|
+
value: 0
|
|
126
|
+
};
|
|
127
|
+
_.merge(fileItem, task);
|
|
128
|
+
if (!task.processing) {
|
|
129
|
+
task.processing = 0;
|
|
130
|
+
}
|
|
131
|
+
task.processing++;
|
|
132
|
+
fileItem.inputTask = task;
|
|
133
|
+
job.emit('progress', fileItem);
|
|
134
|
+
resolve(job);
|
|
135
|
+
})
|
|
136
|
+
.on('end', () => {
|
|
137
|
+
if (!this.processedTasks) {
|
|
138
|
+
this.processedTasks = 0;
|
|
139
|
+
}
|
|
140
|
+
this.processedTasks++;
|
|
141
|
+
// Check processedTasks tasks
|
|
142
|
+
// Manually emit `end` event for all tasks finished
|
|
143
|
+
if (this.processedTasks === this.jobInfo.tasks.length) {
|
|
144
|
+
this.taskStream._flush(() => { });
|
|
145
|
+
this.taskStream.emit('end');
|
|
146
|
+
}
|
|
147
|
+
})
|
|
148
|
+
.pipe(this.taskStream, { end: false });
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
exports.JobProcessor = JobProcessor;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.GraphQLProcessor = void 0;
|
|
13
|
+
const _ = require("lodash");
|
|
14
|
+
const fs = require("fs");
|
|
15
|
+
const index_1 = require("./index");
|
|
16
|
+
const { YamlStreamReadTransformer } = require('yaml-document-stream');
|
|
17
|
+
/**
|
|
18
|
+
* GraphQL-specific job processor.
|
|
19
|
+
*/
|
|
20
|
+
class GraphQLProcessor {
|
|
21
|
+
constructor(opts) {
|
|
22
|
+
if (_.isNil(opts)) {
|
|
23
|
+
throw new Error('Missing options parameter');
|
|
24
|
+
}
|
|
25
|
+
const defaults = {
|
|
26
|
+
diffBase: 'md5'
|
|
27
|
+
};
|
|
28
|
+
_.defaults(opts, defaults);
|
|
29
|
+
this.opts = opts;
|
|
30
|
+
this.client = new index_1.Client(opts);
|
|
31
|
+
}
|
|
32
|
+
process(job) {
|
|
33
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
34
|
+
let yamlStream = new YamlStreamReadTransformer();
|
|
35
|
+
let jobPath = job.path;
|
|
36
|
+
let data = false;
|
|
37
|
+
switch (job.operation) {
|
|
38
|
+
case 'sync': { // synchronous operation
|
|
39
|
+
const fileStream = fs.createReadStream(job.fullPath);
|
|
40
|
+
fileStream.pipe(yamlStream);
|
|
41
|
+
let batchsize;
|
|
42
|
+
if (job.batchSize) {
|
|
43
|
+
batchsize = job.batchSize;
|
|
44
|
+
console.log('Batch size:', batchsize);
|
|
45
|
+
}
|
|
46
|
+
let counter = 0;
|
|
47
|
+
let batchCounter = 0;
|
|
48
|
+
let docArr = [];
|
|
49
|
+
let resultArr = [];
|
|
50
|
+
// Here we read from the readable stream each yaml document parsed
|
|
51
|
+
// as an object, and if we have batching enabled we first batch this
|
|
52
|
+
// documents into smaller sets. When a dataset is ready to be imported,
|
|
53
|
+
// we pause the readable stream and emit a 'pause' event and
|
|
54
|
+
// right after that we reset the dataset object 'docArr'.
|
|
55
|
+
yamlStream.on('data', (doc) => {
|
|
56
|
+
data = true;
|
|
57
|
+
if (batchsize && batchsize != undefined) {
|
|
58
|
+
docArr.push(doc);
|
|
59
|
+
counter++;
|
|
60
|
+
if (counter === batchsize) {
|
|
61
|
+
counter = 0;
|
|
62
|
+
batchCounter++;
|
|
63
|
+
console.log('Processing batch:', batchCounter);
|
|
64
|
+
yamlStream.pause();
|
|
65
|
+
docArr = [];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
docArr.push(doc);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
// On 'pause' event we create a post request using the GQL Client
|
|
73
|
+
// using the accumulated resources inside the 'docArr' dataset,
|
|
74
|
+
// we wait for the response, store the response inside an array and
|
|
75
|
+
// only then we emit a 'resume' event, resuming reading from the
|
|
76
|
+
// 'yamlStream' readable stream.
|
|
77
|
+
yamlStream.on('pause', () => __awaiter(this, void 0, void 0, function* () {
|
|
78
|
+
let result = yield this.client.post(docArr, job);
|
|
79
|
+
resultArr.push(result);
|
|
80
|
+
yamlStream.resume();
|
|
81
|
+
}));
|
|
82
|
+
// On 'end' if we still have data accumulated inside the 'docArr'
|
|
83
|
+
// dataset, we create a final post request to import this data as-well,
|
|
84
|
+
// store the response inside the array and finally resolve this as a
|
|
85
|
+
// Promise to return all the responses back to the initial caller.
|
|
86
|
+
return new Promise((resolve, reject) => {
|
|
87
|
+
yamlStream.on('end', () => __awaiter(this, void 0, void 0, function* () {
|
|
88
|
+
if (data === false) {
|
|
89
|
+
throw new Error(`Could not import resources from ${jobPath}. Readable stream is empty. Please provide a file with YAML multi-document format.`);
|
|
90
|
+
}
|
|
91
|
+
if (docArr && !_.isEmpty(docArr)) {
|
|
92
|
+
batchCounter++;
|
|
93
|
+
console.log('Processing batch:', batchCounter);
|
|
94
|
+
let result = yield this.client.post(docArr, job);
|
|
95
|
+
resultArr.push(result);
|
|
96
|
+
docArr = [];
|
|
97
|
+
resolve(resultArr);
|
|
98
|
+
}
|
|
99
|
+
}));
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
default: {
|
|
103
|
+
throw new Error('Unsupported job operation');
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
exports.GraphQLProcessor = GraphQLProcessor;
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@restorecommerce/gql-bot",
|
|
3
3
|
"description": "GraphQL Client Automated Task Processor",
|
|
4
4
|
"main": "lib/index",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.16",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "https://github.com/restorecommerce/libs.git"
|
|
@@ -59,5 +59,5 @@
|
|
|
59
59
|
"engines": {
|
|
60
60
|
"node": ">= 12.0.0"
|
|
61
61
|
},
|
|
62
|
-
"gitHead": "
|
|
62
|
+
"gitHead": "e97bbfe2fe8166dfe1cd47ae60bce54347a4f1c9"
|
|
63
63
|
}
|