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.
- package/bajo/helper/fetch-and-save.js +70 -13
- package/package.json +1 -1
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
async function
|
|
2
|
-
const { setImmediate, importPkg,
|
|
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))
|
|
23
|
+
if (isEmpty(r)) {
|
|
24
|
+
stat.skipped++
|
|
25
|
+
continue
|
|
26
|
+
}
|
|
20
27
|
try {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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(
|
|
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.
|
|
44
|
-
|
|
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
|