bajo-extra 0.2.10 → 0.2.12

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,104 +1,66 @@
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
- const { fetch } = this.bajoExtra.helper
5
- const { recordCreate, recordFind, recordUpdate, validationErrorMessage } = this.bajoDb.helper
6
- const resp = await fetch(source.url, source.options ?? {})
7
- if (isEmpty(resp)) spin.fatal('No result from server, aborted!')
8
- if (source.abort) {
9
- const aborted = await source.abort.call(this, resp)
10
- if (aborted) spin.fatal(aborted)
1
+ async function handler (rec, bulk) {
2
+ const { importPkg } = this.bajo.helper
3
+ const { isFunction, set } = await importPkg('lodash-es')
4
+ const { recordCreate, recordFind, recordUpdate } = this.bajoDb.helper
5
+ const save = bulk.save ?? {}
6
+ const current = save.current ?? {}
7
+ let existing
8
+ let record
9
+ let method
10
+ save.checkUnique = save.checkUnique ?? 'id'
11
+ if (['unique', 'upsert'].includes(save.mode)) {
12
+ const query = isFunction(save.checkUnique) ? await save.checkUnique.call(this, rec, save) : set({}, save.checkUnique, rec[save.checkUnique])
13
+ const resp = await recordFind(save.coll, { query, limit: 1 }, { skipCache: true })
14
+ if (resp.length > 0) existing = resp[0]
11
15
  }
12
- let count = 0
13
- const stat = { created: 0, updated: 0, skipped: 0, error: 0 }
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
- }
19
- spin.setText('Got %d records, processing...', iterator.length)
20
- for (let r of iterator) {
21
- await setImmediate()
22
- if (converter) r = await converter.call(this, r, options)
23
- if (isEmpty(r)) {
24
- stat.skipped++
25
- continue
16
+ if (existing) {
17
+ if (save.mode === 'upsert') {
18
+ const body = save.updateConverter ? await save.updateConverter.call(this, rec, save) : rec
19
+ try {
20
+ record = await recordUpdate(save.coll, existing.id, body)
21
+ method = 'updated'
22
+ } catch (err) {
23
+ console.error(err)
24
+ method = 'error'
25
+ }
26
+ } else {
27
+ method = 'skipped'
26
28
  }
29
+ } else {
27
30
  try {
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 })
55
- const recs = await recordFind(current.coll, { query }, { skipCache: true })
56
- const rc = current.converter ? await current.converter.call(this, { body: r, record, options }) : r
57
- if (rc) {
58
- if (recs.length > 0) {
59
- const id = recs[0].id
60
- await recordUpdate(current.coll, id, rc)
61
- } else {
62
- await recordCreate(current.coll, rc)
63
- }
64
- }
65
- }
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)
68
- count++
31
+ record = await recordCreate(save.coll, rec)
32
+ method = 'created'
69
33
  } catch (err) {
70
- console.log(err)
71
- spin.setText(validationErrorMessage(err) + ', continue')
34
+ console.error(err)
35
+ method = 'error'
72
36
  }
73
37
  }
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
38
+ if (record && current.coll && current.query) {
39
+ const query = await current.query.call(this, { body: rec, record, opts: save })
40
+ const recs = await recordFind(current.coll, { query }, { skipCache: true })
41
+ const rc = current.converter ? await current.converter.call(this, { body: rec, record, opts: save }) : rec
42
+ if (rc) {
43
+ if (recs.length > 0) {
44
+ const id = recs[0].id
45
+ await recordUpdate(current.coll, id, rc)
46
+ } else {
47
+ await recordCreate(current.coll, rc)
95
48
  }
96
- step++
97
49
  }
98
- } else {
99
- const spin = spinner({ showCounter: true }).start('Fetching starts...')
100
- await batching.call(this, { source, converter, coll, current, options, spin })
101
50
  }
51
+ return method
52
+ }
53
+
54
+ async function fetchAndSave ({ url, bulk, save = {}, opts = {} } = {}) {
55
+ const { importPkg, getConfig, importModule } = this.bajo.helper
56
+ const { fetchBulk } = this.bajoExtra.helper
57
+ const { merge } = await importPkg('lodash-es')
58
+ merge(bulk, { handler, save })
59
+ const cfgDb = getConfig('bajoDb', { full: true })
60
+ const start = await importModule(`${cfgDb.dir.pkg}/bajo/start.js`)
61
+ await start.call(this, 'all')
62
+
63
+ await fetchBulk(url, bulk, opts)
102
64
  }
103
65
 
104
66
  export default fetchAndSave
@@ -0,0 +1,78 @@
1
+ async function fetching ({ url, opts, bulk, spin }) {
2
+ const { setImmediate, importPkg, print } = this.bajo.helper
3
+ const { isEmpty, isFunction, has } = await importPkg('lodash-es')
4
+ const { validationErrorMessage } = this.bajoDb.helper
5
+ const { fetch } = this.bajoExtra.helper
6
+ const resp = await fetch(url, opts ?? {})
7
+ if (isEmpty(resp)) {
8
+ spin.fatal('No result from server, aborted!')
9
+ return -1
10
+ }
11
+ if (bulk.abort) {
12
+ const aborted = await bulk.abort.call(this, resp)
13
+ if (aborted) {
14
+ spin.fatal(aborted)
15
+ return -1
16
+ }
17
+ }
18
+ let count = 0
19
+ const stat = { created: 0, updated: 0, skipped: 0, error: 0 }
20
+ bulk.dataKey = bulk.dataKey ?? 'data'
21
+ if (bulk.printCount === true) bulk.printCount = 100
22
+ const data = isFunction(bulk.dataKey) ? await bulk.dataKey.call(this, resp) : resp[bulk.dataKey]
23
+ if (data.length === 0) {
24
+ print.warn('No records to process, abort')
25
+ return 0
26
+ }
27
+ spin.setText('Got %d records, processing...', data.length)
28
+ for (let r of data) {
29
+ await setImmediate()
30
+ if (bulk.converter) r = await bulk.converter.call(this, r, bulk)
31
+ if (isEmpty(r)) {
32
+ stat.skipped++
33
+ continue
34
+ }
35
+ try {
36
+ const result = await bulk.handler.call(this, r, bulk)
37
+ if (result && has(stat, result)) stat[result]++
38
+ if (bulk.printCount && bulk.printCount < count && (count % bulk.printCount === 0)) print.succeed('[%s] Processed %d/%d', spin.getElapsed(), count, data.length)
39
+ else if (!spin.opts.isLog) spin.setText('Record %d/%d...', count, data.length)
40
+ count++
41
+ } catch (err) {
42
+ console.log(err)
43
+ spin.setText(validationErrorMessage(err) + ', continue')
44
+ }
45
+ }
46
+ print.succeed('[%s] %d/%d records processed', spin.getElapsed(), count, data.length)
47
+ if (!bulk.noStat) print.succeed('[%s] Created: %d, Updated: %d, Skipped: %d', spin.getElapsed(), stat.created, stat.updated, stat.skipped)
48
+ return data.length
49
+ }
50
+
51
+ async function fetchBulk (url, bulk = {}, opts = {}) {
52
+ const { print, spinner, importPkg, error } = this.bajo.helper
53
+ const { isFunction } = await importPkg('lodash-es')
54
+ opts.params = opts.params ?? {}
55
+ bulk.maxStep = bulk.maxStep ?? 0
56
+ if (!isFunction(bulk.handler)) throw error('A function handler must be provided')
57
+ if (isFunction(bulk.paramsIncFn)) {
58
+ print.info('Bulk fetch starting')
59
+ const spin = spinner({ showCounter: true }).start('Fetching starts...')
60
+ let step = 1
61
+ for (;;) {
62
+ print.info('[%s] Batch #%d', spin.getElapsed(), step)
63
+ const newOpts = await bulk.paramsIncFn.call(this, { url, bulk, opts })
64
+ if (newOpts) opts = newOpts
65
+ const length = await fetching.call(this, { url, bulk, opts, spin })
66
+ if (length === 0 || (bulk.maxStep > 0 && step >= bulk.maxStep)) {
67
+ print.info('All done!')
68
+ break
69
+ }
70
+ step++
71
+ }
72
+ } else {
73
+ const spin = spinner({ showCounter: true }).start('Fetching starts...')
74
+ await fetching.call(this, { url, bulk, opts, spin })
75
+ }
76
+ }
77
+
78
+ export default fetchBulk
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bajo-extra",
3
- "version": "0.2.10",
3
+ "version": "0.2.12",
4
4
  "description": "Extra package for Bajo Framework",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -32,6 +32,7 @@
32
32
  "email-addresses": "^5.0.0",
33
33
  "fast-jwt": "^3.2.0",
34
34
  "fast-xml-parser": "^4.3.2",
35
+ "littlehash": "^1.0.1",
35
36
  "ndjson-csv-xlsx": "^1.1.1",
36
37
  "performant-array-to-tree": "^1.11.0",
37
38
  "query-string": "^8.1.0",