@miso.ai/server-sdk 0.6.3-beta.9 → 0.6.4-beta.0

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/cli/get.js ADDED
@@ -0,0 +1,23 @@
1
+ import { MisoClient } from '../src/index.js';
2
+
3
+ const build = yargs => yargs;
4
+
5
+ const run = type => async ({
6
+ key,
7
+ server,
8
+ id,
9
+ debug,
10
+ }) => {
11
+ const client = new MisoClient({ key, server });
12
+ const entity = await client.api[type].get(id);
13
+ console.log(JSON.stringify(entity));
14
+ };
15
+
16
+ export default function(type) {
17
+ return {
18
+ command: 'get [id]',
19
+ description: `Get ${type}`,
20
+ builder: build,
21
+ handler: run(type),
22
+ };
23
+ }
package/cli/index.js CHANGED
@@ -1,17 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import { yargs } from '@miso.ai/server-commons';
3
3
  import { MisoClient } from '../src/index.js';
4
+ import { buildForApi } from './utils.js';
5
+ import merge from './merge.js';
4
6
  import upload from './upload.js';
5
7
  import del from './delete.js';
6
8
  import ids from './ids.js';
7
9
  import transform from './transform.js';
8
10
  import status from './status.js';
11
+ import get from './get.js';
9
12
 
10
13
  const interactions = {
11
14
  command: 'interactions',
12
15
  aliases: ['interaction', 'i'],
13
16
  description: 'Interaction commands',
14
- builder: yargs => _buildForApi(yargs)
17
+ builder: yargs => buildForApi(yargs)
15
18
  .command(upload('interactions')),
16
19
  };
17
20
 
@@ -19,10 +22,12 @@ const products = {
19
22
  command: 'products',
20
23
  aliases: ['product', 'p', 'catalog'],
21
24
  description: 'Product commands',
22
- builder: yargs => _buildForApi(yargs)
25
+ builder: yargs => buildForApi(yargs)
23
26
  .command(upload('products'))
24
27
  .command(del('products'))
25
28
  .command(ids('products'))
29
+ .command(get('products'))
30
+ .command(merge('products'))
26
31
  .command(status('products')),
27
32
  };
28
33
 
@@ -30,10 +35,12 @@ const users = {
30
35
  command: 'users',
31
36
  aliases: ['user', 'u'],
32
37
  description: 'User commands',
33
- builder: yargs => _buildForApi(yargs)
38
+ builder: yargs => buildForApi(yargs)
34
39
  .command(upload('users'))
35
40
  .command(del('users'))
36
41
  .command(ids('users'))
42
+ .command(get('users'))
43
+ .command(merge('users'))
37
44
  .command(status('users')),
38
45
  };
39
46
 
@@ -41,7 +48,7 @@ const experiments = {
41
48
  command: 'experiments',
42
49
  aliases: ['experiment'],
43
50
  description: 'Experiment commands',
44
- builder: yargs => _buildForApi(yargs)
51
+ builder: yargs => buildForApi(yargs)
45
52
  .option('experiment-id', {
46
53
  alias: ['exp-id'],
47
54
  describe: 'Experiment ID for experiment API',
@@ -63,29 +70,3 @@ yargs.build(yargs => {
63
70
  .command(transform)
64
71
  .version(MisoClient.version);
65
72
  });
66
-
67
-
68
-
69
- // helpers //
70
- function _buildForApi(yargs) {
71
- return yargs
72
- .option('key', {
73
- alias: ['k', 'api-key'],
74
- describe: 'API key',
75
- })
76
- .option('server', {
77
- alias: ['api-server'],
78
- describe: 'API server',
79
- })
80
- .option('param', {
81
- alias: ['v', 'var'],
82
- describe: 'Extra URL parameters',
83
- type: 'array',
84
- coerce: yargs.coerceToArray,
85
- })
86
- .option('debug', {
87
- describe: 'Set log level to debug',
88
- type: 'boolean',
89
- })
90
- .demandOption(['key'], 'API key is required.');
91
- }
package/cli/merge.js ADDED
@@ -0,0 +1,39 @@
1
+ import split2 from 'split2';
2
+ import { stream } from '@miso.ai/server-commons';
3
+ import { MisoClient } from '../src/index.js';
4
+
5
+ function build(yargs) {
6
+ return yargs
7
+ .option('file', {
8
+ alias: ['f'],
9
+ describe: 'File that contains the merge function',
10
+ });
11
+ }
12
+
13
+ const run = type => async ({
14
+ key,
15
+ server,
16
+ file,
17
+ ...options
18
+ }) => {
19
+ // TODO: load merge function
20
+ const client = new MisoClient({ key, server });
21
+ const mergeStream = client.api[type].mergeStream(options);
22
+ const outputStream = new stream.OutputStream({ objectMode: true });
23
+ await stream.pipeline(
24
+ process.stdin,
25
+ split2(),
26
+ stream.parse(),
27
+ mergeStream,
28
+ outputStream
29
+ );
30
+ }
31
+
32
+ export default function(type) {
33
+ return {
34
+ command: 'merge',
35
+ description: `Merge records with existing ${type} in catalog.`,
36
+ builder: build,
37
+ handler: run(type),
38
+ };
39
+ }
package/cli/utils.js ADDED
@@ -0,0 +1,22 @@
1
+ export function buildForApi(yargs) {
2
+ return yargs
3
+ .option('key', {
4
+ alias: ['k', 'api-key'],
5
+ describe: 'API key',
6
+ })
7
+ .option('server', {
8
+ alias: ['api-server'],
9
+ describe: 'API server',
10
+ })
11
+ .option('param', {
12
+ alias: ['v', 'var'],
13
+ describe: 'Extra URL parameters',
14
+ type: 'array',
15
+ coerce: yargs.coerceToArray,
16
+ })
17
+ .option('debug', {
18
+ describe: 'Set log level to debug',
19
+ type: 'boolean',
20
+ })
21
+ .demandOption(['key'], 'API key is required.');
22
+ }
package/package.json CHANGED
@@ -16,11 +16,11 @@
16
16
  "simonpai <simon.pai@askmiso.com>"
17
17
  ],
18
18
  "dependencies": {
19
- "@miso.ai/server-commons": "0.6.3-beta.9",
20
- "axios": "^0.27.2",
19
+ "@miso.ai/server-commons": "0.6.4-beta.0",
20
+ "axios": "^1.6.2",
21
21
  "dotenv": "^16.0.1",
22
22
  "split2": "^4.1.0",
23
23
  "yargs": "^17.5.1"
24
24
  },
25
- "version": "0.6.3-beta.9"
25
+ "version": "0.6.4-beta.0"
26
26
  }
package/src/api/base.js CHANGED
@@ -1,8 +1,10 @@
1
1
  import axios from 'axios';
2
- import { upload, batchDelete, buildUrl } from './helpers.js';
2
+ import { asArray } from '@miso.ai/server-commons';
3
+ import { upload, merge, batchDelete, buildUrl } from './helpers.js';
3
4
  import UploadStream from '../stream/upload.js';
4
5
  import DeleteStream from '../stream/delete.js';
5
6
  import StatusStream from '../stream/status.js';
7
+ import MergeStream from '../stream/merge.js';
6
8
 
7
9
  export class Queries {
8
10
 
@@ -69,4 +71,13 @@ export class Entities extends Writable {
69
71
  return new StatusStream(this._client, this._type);
70
72
  }
71
73
 
74
+ async merge(records, options = {}) {
75
+ records = asArray(records);
76
+ return await Promise.all(records.map(record => merge(this._client, this._type, record, options)));
77
+ }
78
+
79
+ mergeStream(options = {}) {
80
+ return new MergeStream(this._client, this._type, options);
81
+ }
82
+
72
83
  }
@@ -8,6 +8,46 @@ export async function upload(client, type, records, options = {}) {
8
8
  return axios.post(url, payload);
9
9
  }
10
10
 
11
+ export async function merge(client, type, record, { mergeFn = defaultMerge } = {}) {
12
+ let idProp;
13
+ switch (type) {
14
+ case 'products':
15
+ idProp = 'product_id';
16
+ break;
17
+ case 'users':
18
+ idProp = 'user_id';
19
+ break;
20
+ default:
21
+ throw new Error(`Unsupported type: ${type}`);
22
+ }
23
+ const id = record[idProp];
24
+ if (!id) {
25
+ throw new Error(`Record missing ${idProp}.`);
26
+ }
27
+ const base = shimRecordForMerging(await client.api[type].get(id));
28
+ return await mergeFn(base, record);
29
+ }
30
+
31
+ function defaultMerge(base, patch) {
32
+ return {
33
+ ...base,
34
+ ...patch,
35
+ custom_attributes: {
36
+ ...base.custom_attributes,
37
+ ...patch.custom_attributes,
38
+ },
39
+ };
40
+ }
41
+
42
+ function shimRecordForMerging(record) {
43
+ for (const key in record) {
44
+ if (key === 'product_group_id_or_product_id' || key.startsWith('category_path_')) {
45
+ delete record[key];
46
+ }
47
+ }
48
+ return record;
49
+ }
50
+
11
51
  const RE_422_MSG_LINE = /^\s*data\.(\d+)(?:\.(\S+))?\s+is\s+invalid\.\s+(.*)$/;
12
52
 
13
53
  export function process422ResponseBody(payload, { data } = {}) {
package/src/api/index.js CHANGED
@@ -1,9 +1,12 @@
1
+ import { asArray } from '@miso.ai/server-commons';
2
+ import { merge } from './helpers.js';
1
3
  import Products from './products.js';
2
4
  import Users from './users.js';
3
5
  import Interactions from './interactions.js';
4
6
  import Experiments from './experiments.js';
5
7
  import Search from './search.js';
6
8
  import Recommendation from './recommendation.js';
9
+ import MergeStream from '../stream/merge.js';
7
10
 
8
11
  export default class Api {
9
12
 
@@ -11,7 +11,7 @@ export function createLogStream({
11
11
  format,
12
12
  out,
13
13
  err,
14
- }) {
14
+ } = {}) {
15
15
  switch (format || FORMAT.JSON) {
16
16
  case FORMAT.PROGRESS:
17
17
  switch (api) {
@@ -63,7 +63,7 @@ export class Stream extends Transform {
63
63
  this._transformFn = getTransformFunction(type);
64
64
  }
65
65
 
66
- async _transform(record, _, next) {
66
+ _transform(record, _, next) {
67
67
  try {
68
68
  next(undefined, this._transformFn(record));
69
69
  } catch (error) {
@@ -0,0 +1,22 @@
1
+ import { stream } from '@miso.ai/server-commons';
2
+ import { merge } from '../api/helpers.js';
3
+
4
+ export default class MergeStream extends stream.ParallelTransform {
5
+
6
+ constructor(client, type, {
7
+ mergeFn,
8
+ } = {}) {
9
+ super({
10
+ transform: (record) => merge(client, type, record, { mergeFn }),
11
+ controls: {
12
+ throttle: 100,
13
+ },
14
+ objectMode: true,
15
+ });
16
+ }
17
+
18
+ _error(error) {
19
+ console.error(error);
20
+ }
21
+
22
+ }
@@ -10,7 +10,7 @@ export default class StatusStream extends Transform {
10
10
  this._type = type;
11
11
  }
12
12
 
13
- async _transform(task_id, _) {
13
+ async _transform(task_id, _, next) {
14
14
  try {
15
15
  this.push({
16
16
  task_id,
@@ -23,6 +23,7 @@ export default class StatusStream extends Transform {
23
23
  error: summarizeError(err),
24
24
  });
25
25
  }
26
+ next();
26
27
  }
27
28
 
28
29
  }
package/src/version.js CHANGED
@@ -1 +1 @@
1
- export default '0.6.3-beta.9';
1
+ export default '0.6.4-beta.0';