@miso.ai/server-sdk 0.6.6-beta.3 → 0.6.6-beta.4

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.
@@ -1,116 +1,127 @@
1
1
  #!/usr/bin/env node
2
2
  import 'dotenv/config';
3
- import { promisify } from 'util';
4
- import { readFile } from 'fs/promises';
5
- import { gunzip } from 'zlib';
6
- import { Transform } from 'stream';
3
+ import { join } from 'path';
4
+ import { createReadStream } from 'fs';
5
+ import { createGunzip } from 'zlib';
7
6
  import { pipeline } from 'stream/promises';
8
- import { stream, trimObj } from '@miso.ai/server-commons';
7
+ import { chain } from 'stream-chain';
9
8
  import split2 from 'split2';
9
+ import { stream, trimObj } from '@miso.ai/server-commons';
10
+
11
+ const PWD = process.env.PWD;
10
12
 
11
13
  process.stdout.on('error', err => err.code == 'EPIPE' && process.exit(0));
12
14
 
13
15
  function build(yargs) {
14
16
  return yargs
15
- .positional('file', {
16
- describe: 'Patch record file',
17
+ .positional('file1', {
18
+ describe: 'First record file',
17
19
  type: 'string',
18
20
  demandOption: true,
21
+ })
22
+ .positional('file2', {
23
+ describe: 'Second record file',
24
+ type: 'string',
25
+ })
26
+ .option('join-mode', {
27
+ alias: 'm',
28
+ describe: 'Join mode',
29
+ type: 'string',
30
+ default: 'merge',
31
+ choices: ['merge', 'rewrite-meta', 'remeta'],
32
+ })
33
+ .option('join-function', {
34
+ alias: 'f',
35
+ describe: 'Join function',
36
+ type: 'string',
37
+ })
38
+ .option('stdin', {
39
+ alias: 'i',
40
+ describe: 'Read the first stream from stdin',
41
+ type: 'boolean',
42
+ default: false,
19
43
  });
20
44
  }
21
45
 
22
- async function run({ file }) {
23
- const patches = await readRecordsIntoMap(file);
24
- await pipeline(
25
- process.stdin,
46
+ async function run({ file1, file2, stdin, joinMode, joinFunction }) {
47
+ if (stdin) {
48
+ file2 = file1;
49
+ file1 = undefined;
50
+ } else if (!file2) {
51
+ throw new Error('Second file is required');
52
+ }
53
+ const stream1 = chain([
54
+ stdin ? process.stdin : createReadStream(file1),
55
+ ...(file1 && file1.endsWith('.gz')) ? [createGunzip()] : [],
56
+ split2(JSON.parse),
57
+ ]);
58
+ const stream2 = chain([
59
+ createReadStream(file2),
60
+ ...(file2 && file2.endsWith('.gz')) ? [createGunzip()] : [],
26
61
  split2(JSON.parse),
27
- new MergeLocalStream({ patches }),
62
+ ]);
63
+ await pipeline(
64
+ stream.joinStreams([stream1, stream2], await getJoinFunction(joinMode, joinFunction)),
28
65
  new stream.OutputStream(),
29
66
  );
30
67
  }
31
68
 
32
- async function readRecordsIntoMap(file) {
33
- const map = new Map();
34
- const content = await readContent(file);
35
- for (let line of content.split('\n')) {
36
- line = line.trim();
37
- if (!line) {
38
- continue;
39
- }
69
+ async function getJoinFunction(joinMode, joinFunction) {
70
+ if (joinFunction) {
40
71
  try {
41
- const record = JSON.parse(line);
42
- const { product_id } = record;
43
- if (!product_id) {
44
- console.error(`Missing product_id: ${line}`);
45
- continue;
72
+ const fn = await import(join(PWD, joinFunction));
73
+ if (!fn.default) {
74
+ throw new Error('Join function must have a default export');
46
75
  }
47
- map.set(product_id, record);
48
- } catch (error) {
49
- console.error(`Error parsing JSON line: ${line}`, error);
76
+ return fn.default;
77
+ } catch (e) {
78
+ console.error(`Failed to load join function ${joinFunction}:`, e);
79
+ process.exit(1);
50
80
  }
51
81
  }
52
- return map;
53
- }
54
-
55
- async function readContent(file) {
56
- let fileBuffer = await readFile(file);
57
- if (file.endsWith('.gz')) {
58
- fileBuffer = await promisify(gunzip)(fileBuffer);
82
+ switch (joinMode) {
83
+ case 'merge':
84
+ return merge;
85
+ case 'rewrite-meta':
86
+ case 'remeta':
87
+ return rewriteMeta;
88
+ default:
89
+ throw new Error(`Unsupported join mode: ${joinMode}`);
59
90
  }
60
- return fileBuffer.toString('utf-8');
61
91
  }
62
92
 
63
- class MergeLocalStream extends Transform {
64
-
65
- constructor({
66
- patches,
67
- ...options
68
- } = {}) {
69
- super({
70
- objectMode: true,
71
- ...options,
72
- });
73
- this._patches = patches;
74
- this.on('drain', () => this._handleDrain());
75
- }
76
-
77
- _transform(record, _, next) {
78
- const patch = this._patches.get(record.product_id);
79
- if (patch) {
80
- record = this._patch(record, patch);
81
- }
82
-
83
- const pause = !this.push(record);
84
- if (pause) {
85
- this._next = next;
86
- } else {
87
- next();
88
- }
89
- }
93
+ function merge(record1, record2) {
94
+ assertSameProductId(record1, record2);
95
+ return trimObj({
96
+ ...record1,
97
+ ...record2,
98
+ custom_attributes: trimObj({
99
+ ...(record1 && record1.custom_attributes),
100
+ ...(record2 && record2.custom_attributes),
101
+ }),
102
+ });
103
+ }
90
104
 
91
- _patch(record, patch) {
92
- patch = trimObj(patch);
93
- return {
94
- ...record,
95
- ...patch,
96
- custom_attributes: trimObj({
97
- ...(record && record.custom_attributes),
98
- ...(patch && patch.custom_attributes),
99
- }),
100
- };
101
- }
105
+ function rewriteMeta(record1, record2) {
106
+ assertSameProductId(record1, record2);
107
+ const { description, html, children } = record1;
108
+ const { description: _0, html: _1, children: _2, ...rest } = record2;
109
+ return trimObj({
110
+ ...rest,
111
+ description,
112
+ html,
113
+ children,
114
+ });
115
+ }
102
116
 
103
- _handleDrain() {
104
- if (this._next) {
105
- this._next();
106
- }
117
+ function assertSameProductId(record1, record2) {
118
+ if (record1.product_id !== record2.product_id) {
119
+ throw new Error(`Product IDs do not match: ${record1.product_id} and ${record2.product_id}`);
107
120
  }
108
-
109
121
  }
110
122
 
111
-
112
123
  export default {
113
- command: 'merge-local <file>',
124
+ command: 'merge-local <file1> [file2]',
114
125
  alias: ['patch-local'],
115
126
  description: 'Apply patch records from file onto input record stream',
116
127
  builder: build,
package/package.json CHANGED
@@ -16,12 +16,12 @@
16
16
  "simonpai <simon.pai@askmiso.com>"
17
17
  ],
18
18
  "dependencies": {
19
- "@miso.ai/server-commons": "0.6.6-beta.3",
19
+ "@miso.ai/server-commons": "0.6.6-beta.4",
20
20
  "axios": "^1.6.2",
21
21
  "axios-retry": "^4.5.0",
22
22
  "dotenv": "^16.0.1",
23
23
  "split2": "^4.1.0",
24
24
  "yargs": "^17.5.1"
25
25
  },
26
- "version": "0.6.6-beta.3"
26
+ "version": "0.6.6-beta.4"
27
27
  }
package/src/version.js CHANGED
@@ -1 +1 @@
1
- export default '0.6.6-beta.3';
1
+ export default '0.6.6-beta.4';