bajo-extra 0.2.9 → 0.2.10

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,9 +1,8 @@
1
- async function fetchAndSave ({ source = {}, converter, coll, current = {}, options = {} } = {}) {
2
- const { setImmediate, importPkg, spinner, print } = this.bajo.helper
3
- const { isEmpty, isFunction } = await importPkg('lodash-es')
1
+ async function batching ({ source = {}, converter, coll, current = {}, options = {}, spin } = {}) {
2
+ const { setImmediate, importPkg, print } = this.bajo.helper
3
+ const { isEmpty, isFunction, set } = await importPkg('lodash-es')
4
4
  const { fetch } = this.bajoExtra.helper
5
5
  const { recordCreate, recordFind, recordUpdate, validationErrorMessage } = this.bajoDb.helper
6
- const spin = spinner({ showCounter: true }).start('Fetching starts...')
7
6
  const resp = await fetch(source.url, source.options ?? {})
8
7
  if (isEmpty(resp)) spin.fatal('No result from server, aborted!')
9
8
  if (source.abort) {
@@ -11,18 +10,50 @@ async function fetchAndSave ({ source = {}, converter, coll, current = {}, optio
11
10
  if (aborted) spin.fatal(aborted)
12
11
  }
13
12
  let count = 0
13
+ const stat = { created: 0, updated: 0, skipped: 0, error: 0 }
14
14
  const iterator = isFunction(source.iterator) ? await source.iterator.call(this, resp) : resp[source.iterator]
15
+ if (iterator.length === 0) {
16
+ print.warn('No records to process, abort')
17
+ return 0
18
+ }
15
19
  spin.setText('Got %d records, processing...', iterator.length)
16
20
  for (let r of iterator) {
17
21
  await setImmediate()
18
22
  if (converter) r = await converter.call(this, r, options)
19
- if (isEmpty(r)) continue
23
+ if (isEmpty(r)) {
24
+ stat.skipped++
25
+ continue
26
+ }
20
27
  try {
21
- await recordCreate(coll, r)
22
- if (current.coll && current.query) {
23
- const query = await current.query.call(this, r)
28
+ let existing
29
+ let record
30
+ let method
31
+ options.checkUnique = options.checkUnique ?? 'id'
32
+ if (['unique', 'upsert'].includes(options.mode)) {
33
+ const query = isFunction(options.checkUnique) ? await options.checkUnique.call(this, r, options) : set({}, options.checkUnique, r[options.checkUnique])
34
+ const resp = await recordFind(coll, { query, limit: 1 }, { skipCache: true })
35
+ if (resp.length > 0) existing = resp[0]
36
+ }
37
+ if (existing) {
38
+ if (options.mode === 'upsert') {
39
+ const body = options.updateConverter ? await options.updateConverter.call(this, r, options) : r
40
+ record = await recordUpdate(coll, existing.id, body)
41
+ method = 'updated'
42
+ stat.updated++
43
+ } else {
44
+ stat.skipped++
45
+ print.warn(`[${spin.getElapsed()}] Record %s exists, skipped`, JSON.stringify(r))
46
+ method = 'skipped'
47
+ }
48
+ } else {
49
+ stat.created++
50
+ record = await recordCreate(coll, r)
51
+ method = 'created'
52
+ }
53
+ if (record && current.coll && current.query) {
54
+ const query = await current.query.call(this, { body: r, record, options })
24
55
  const recs = await recordFind(current.coll, { query }, { skipCache: true })
25
- const rc = current.converter ? await current.converter.call(this, r, options) : r
56
+ const rc = current.converter ? await current.converter.call(this, { body: r, record, options }) : r
26
57
  if (rc) {
27
58
  if (recs.length > 0) {
28
59
  const id = recs[0].id
@@ -32,16 +63,42 @@ async function fetchAndSave ({ source = {}, converter, coll, current = {}, optio
32
63
  }
33
64
  }
34
65
  }
35
- if (options.printCount && (count % options.printCount === 0)) print.succeed(`[${spin.getElapsed()}] Batch line %d/%d`, count, iterator.length)
36
- else if (!spin.opts.isLog) spin.setText('Record %d/%d...', count, iterator.length)
66
+ if (options.printCount && options.printCount < count && (count % options.printCount === 0)) print.succeed('[%s] Processed %d/%d', spin.getElapsed(), count, iterator.length)
67
+ else if (!spin.opts.isLog) spin.setText('Record %d/%d...', count, iterator.length, method)
37
68
  count++
38
69
  } catch (err) {
39
70
  console.log(err)
40
71
  spin.setText(validationErrorMessage(err) + ', continue')
41
72
  }
42
73
  }
43
- spin.info(`${count}/${iterator.length} records processed`)
44
- spin.succeed('Done!')
74
+ print.succeed('[%s] %d/%d records processed', spin.getElapsed(), count, iterator.length)
75
+ print.succeed('[%s] Created: %d, Updated: %d, Skipped: %d', spin.getElapsed(), stat.created, stat.updated, stat.skipped)
76
+ return iterator.length
77
+ }
78
+
79
+ async function fetchAndSave ({ source = {}, converter, coll, current = {}, options = {} } = {}) {
80
+ const { print, spinner } = this.bajo.helper
81
+ source.options = source.options ?? {}
82
+ source.options.params = source.options.params ?? {}
83
+ if (options.batch) {
84
+ print.info('Batch starting')
85
+ const spin = spinner({ showCounter: true }).start('Fetching starts...')
86
+ let step = 1
87
+ for (;;) {
88
+ print.info('[%s] Fetch batch #%d', spin.getElapsed(), step)
89
+ const newSource = await options.batch.call(this, source)
90
+ if (newSource) source = newSource
91
+ const length = await batching.call(this, { source, converter, coll, current, options, spin })
92
+ if (length === 0) {
93
+ print.info('All done!')
94
+ break
95
+ }
96
+ step++
97
+ }
98
+ } else {
99
+ const spin = spinner({ showCounter: true }).start('Fetching starts...')
100
+ await batching.call(this, { source, converter, coll, current, options, spin })
101
+ }
45
102
  }
46
103
 
47
104
  export default fetchAndSave
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bajo-extra",
3
- "version": "0.2.9",
3
+ "version": "0.2.10",
4
4
  "description": "Extra package for Bajo Framework",
5
5
  "main": "index.js",
6
6
  "scripts": {