bajo-extra 0.2.17 → 0.3.1

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/config.json CHANGED
@@ -2,18 +2,5 @@
2
2
  "alias": "x",
3
3
  "fetch": {
4
4
  "agent": {}
5
- },
6
- "stream": {
7
- "export": {
8
- "maxBatch": 1000,
9
- "stringify": {
10
- "open": "[\n",
11
- "sep": ",\n",
12
- "close": "\n]\n"
13
- }
14
- },
15
- "import": {
16
- "maxBatch": 1000
17
- }
18
5
  }
19
6
  }
@@ -1,11 +1,11 @@
1
1
  import path from 'path'
2
2
 
3
3
  async function download (url, opts = {}) {
4
- const { getPluginDataDir, importPkg, error, generateId } = this.bajo.helper
4
+ const { fs, getPluginDataDir, importPkg, error, generateId } = this.bajo.helper
5
5
  const { fetch, formatByte, formatPercentage } = this.bajoExtra.helper
6
- const { isFunction } = await importPkg('lodash-es')
6
+ const { isFunction } = this.bajo.helper._
7
7
  if (typeof opts === 'string') opts = { dir: opts }
8
- const [fs, increment] = await importPkg('fs-extra', 'add-filename-increment')
8
+ const increment = await importPkg('add-filename-increment')
9
9
  if (!opts.dir) {
10
10
  opts.dir = `${getPluginDataDir('bajoExtra')}/download`
11
11
  fs.ensureDirSync(opts.dir)
@@ -1,6 +1,5 @@
1
1
  async function handler (rec, bulk) {
2
- const { importPkg } = this.bajo.helper
3
- const { isFunction, set } = await importPkg('lodash-es')
2
+ const { isFunction, set } = this.bajo.helper._
4
3
  const { recordCreate, recordFind, recordUpdate } = this.bajoDb.helper
5
4
  const save = bulk.save ?? {}
6
5
  const current = save.current ?? {}
@@ -52,13 +51,11 @@ async function handler (rec, bulk) {
52
51
  }
53
52
 
54
53
  async function fetchAndSave ({ url, bulk, save = {}, opts = {} } = {}) {
55
- const { importPkg, getConfig, importModule } = this.bajo.helper
54
+ const { startPlugin } = this.bajo.helper
56
55
  const { fetchBulk } = this.bajoExtra.helper
57
- const { merge } = await importPkg('lodash-es')
56
+ const { merge } = this.bajo.helper._
58
57
  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')
58
+ await startPlugin('bajoDb')
62
59
 
63
60
  await fetchBulk(url, bulk, opts)
64
61
  }
@@ -1,6 +1,6 @@
1
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')
2
+ const { setImmediate, print } = this.bajo.helper
3
+ const { isEmpty, isFunction, has } = this.bajo.helper._
4
4
  const { validationErrorMessage } = this.bajoDb.helper
5
5
  const { fetch } = this.bajoExtra.helper
6
6
  const resp = await fetch(url, opts ?? {})
@@ -49,8 +49,8 @@ async function fetching ({ url, opts, bulk, spin }) {
49
49
  }
50
50
 
51
51
  async function fetchBulk (url, bulk = {}, opts = {}) {
52
- const { print, spinner, importPkg, error } = this.bajo.helper
53
- const { isFunction } = await importPkg('lodash-es')
52
+ const { print, spinner, error } = this.bajo.helper
53
+ const { isFunction } = this.bajo.helper._
54
54
  opts.params = opts.params ?? {}
55
55
  bulk.maxStep = bulk.maxStep ?? 0
56
56
  if (!isFunction(bulk.handler)) throw error('A function handler must be provided')
@@ -3,8 +3,8 @@ import http from 'http'
3
3
  import https from 'https'
4
4
 
5
5
  async function fetch (url, opts = {}, ext = {}) {
6
- const { importPkg, getConfig } = this.bajo.helper
7
- const { has, isPlainObject, cloneDeep, isEmpty } = await importPkg('lodash-es')
6
+ const { getConfig } = this.bajo.helper
7
+ const { has, isPlainObject, cloneDeep, isEmpty } = this.bajo.helper._
8
8
  const cfg = getConfig('bajoExtra')
9
9
  if (isPlainObject(url)) {
10
10
  ext = cloneDeep(opts)
@@ -1,22 +1,19 @@
1
1
  import { createGzip, createGunzip } from 'zlib'
2
2
 
3
3
  function gzip (file, deleteOld, expand) {
4
+ const { fs } = this.bajo.helper
4
5
  return new Promise((resolve, reject) => {
5
- const { importPkg } = this.bajo.helper
6
- importPkg('fs-extra')
7
- .then(fs => {
8
- const newFile = expand ? file.slice(0, file.length - 3) : (file + '.gz')
9
- const reader = fs.createReadStream(file)
10
- const writer = fs.createWriteStream(newFile)
11
- const method = expand ? createGunzip() : createGzip()
12
- reader.pipe(method).pipe(writer)
13
- writer.on('error', reject)
14
- writer.on('finish', err => {
15
- if (err) return reject(err)
16
- if (deleteOld) fs.unlinkSync(file)
17
- resolve()
18
- })
19
- })
6
+ const newFile = expand ? file.slice(0, file.length - 3) : (file + '.gz')
7
+ const reader = fs.createReadStream(file)
8
+ const writer = fs.createWriteStream(newFile)
9
+ const method = expand ? createGunzip() : createGzip()
10
+ reader.pipe(method).pipe(writer)
11
+ writer.on('error', reject)
12
+ writer.on('finish', err => {
13
+ if (err) return reject(err)
14
+ if (deleteOld) fs.unlinkSync(file)
15
+ resolve()
16
+ })
20
17
  })
21
18
  }
22
19
 
package/bajoCli/tool.js CHANGED
@@ -1,8 +1 @@
1
- async function tool ({ path, args = [] }) {
2
- const { currentLoc } = this.bajo.helper
3
- const { runToolMethod } = this.bajoCli.helper
4
- const options = { demonize: ['shell'] }
5
- await runToolMethod({ path, args, dir: `${currentLoc(import.meta).dir}/tool`, options })
6
- }
7
-
8
- export default tool
1
+ export default 'defCliHandler'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bajo-extra",
3
- "version": "0.2.17",
3
+ "version": "0.3.1",
4
4
  "description": "Extra package for Bajo Framework",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -26,21 +26,13 @@
26
26
  },
27
27
  "homepage": "https://github.com/ardhi/bajo-extra#readme",
28
28
  "dependencies": {
29
- "@atomictech/xlsx-write-stream": "^2.0.2",
30
29
  "async": "^3.2.4",
31
30
  "axios": "^1.4.0",
32
31
  "bcrypt": "^5.1.1",
33
32
  "email-addresses": "^5.0.0",
34
- "fast-csv": "^5.0.1",
35
- "fast-jwt": "^3.2.0",
36
- "fast-xml-parser": "^4.3.2",
37
- "ndjson": "^2.0.0",
33
+ "fast-xml-parser": "^4.3.6",
38
34
  "numbro": "^2.5.0",
39
35
  "performant-array-to-tree": "^1.11.0",
40
- "query-string": "^8.1.0",
41
- "scramjet": "^4.36.9",
42
- "stream-chain": "^2.2.5",
43
- "stream-json": "^1.8.0",
44
- "xlsx-parse-stream": "^1.1.0"
36
+ "query-string": "^8.1.0"
45
37
  }
46
38
  }
@@ -1,115 +0,0 @@
1
- import path from 'path'
2
- import scramjet from 'scramjet'
3
- import format from '../../lib/ndjson-csv-xlsx.js'
4
- import { createGzip } from 'zlib'
5
-
6
- const { json, ndjson, csv, xlsx } = format
7
- const { DataStream } = scramjet
8
-
9
- const supportedExt = ['.json', '.jsonl', '.ndjson', '.csv', '.xlsx', '.tsv']
10
-
11
- async function getFile (dest, ensureDir) {
12
- const { importPkg, error, getPluginDataDir } = this.bajo.helper
13
- const [fs, increment] = await importPkg('fs-extra', 'add-filename-increment')
14
- let file
15
- if (path.isAbsolute(dest)) file = dest
16
- else {
17
- file = `${getPluginDataDir('bajoExtra')}/export/${dest}`
18
- fs.ensureDirSync(path.dirname(file))
19
- }
20
- file = increment(file, { fs: true })
21
- const dir = path.dirname(file)
22
- if (!fs.existsSync(dir)) {
23
- if (ensureDir) fs.ensureDirSync(dir)
24
- else throw error('Directory \'%s\' doesn\'t exist', dir)
25
- }
26
- let compress = false
27
- let ext = path.extname(file)
28
- if (ext === '.gz') {
29
- compress = true
30
- ext = path.extname(path.basename(file).replace('.gz', ''))
31
- // file = file.slice(0, file.length - 3)
32
- }
33
- if (!supportedExt.includes(ext)) throw error('Unsupported format \'%s\'', ext.slice(1))
34
- return { file, ext, compress }
35
- }
36
-
37
- async function getData ({ source, filter, count, stream, progressFn }) {
38
- let cnt = count ?? 0
39
- const { recordFind } = this.bajoDb.helper
40
- for (;;) {
41
- const batchStart = new Date()
42
- const { data, page } = await recordFind(source, filter, { dataOnly: false })
43
- if (data.length === 0) break
44
- cnt += data.length
45
- await stream.pull(data)
46
- if (progressFn) await progressFn.call(this, { batchNo: page, data, batchStart, batchEnd: new Date() })
47
- filter.page++
48
- }
49
- await stream.end()
50
- return cnt
51
- }
52
-
53
- function exportTo (source, dest, { filter = {}, ensureDir, useHeader = true, batch = 500, progressFn } = {}, opts = {}) {
54
- const { error, importPkg, getConfig } = this.bajo.helper
55
- const cfg = getConfig('bajoExtra')
56
- if (!this.bajoDb) throw error('Bajo DB isn\'t loaded')
57
- filter.page = 1
58
- batch = parseInt(batch) ?? 500
59
- if (batch > cfg.stream.export.maxBatch) batch = cfg.stream.export.maxBatch
60
- if (batch < 0) batch = 1
61
- filter.limit = batch
62
-
63
- return new Promise((resolve, reject) => {
64
- const { getInfo } = this.bajoDb.helper
65
- let count = 0
66
- let fs
67
- let merge
68
- let file
69
- let ext
70
- let stream
71
- let compress
72
- let writer
73
- getInfo(source)
74
- .then(() => {
75
- return importPkg('lodash-es')
76
- })
77
- .then(l => {
78
- merge = l.merge
79
- return importPkg('fs-extra')
80
- })
81
- .then(res => {
82
- fs = res
83
- return getFile.call(this, dest, ensureDir)
84
- })
85
- .then(res => {
86
- file = res.file
87
- ext = res.ext
88
- compress = res.compress
89
- writer = fs.createWriteStream(file)
90
- writer.on('error', err => {
91
- reject(err)
92
- })
93
- writer.on('finish', () => {
94
- resolve({ file, count })
95
- })
96
- stream = new DataStream()
97
- stream = stream.flatMap(items => (items))
98
- const pipes = []
99
- if (ext === '.json') pipes.push(json.stringify(opts))
100
- else if (['.ndjson', '.jsonl'].includes(ext)) pipes.push(ndjson.stringify(opts))
101
- else if (ext === '.csv') pipes.push(csv.stringify(merge({}, { headers: useHeader }, opts)))
102
- else if (ext === '.tsv') pipes.push(csv.stringify(merge({}, { headers: useHeader }, merge({}, opts, { delimiter: '\t' }))))
103
- else if (ext === '.xlsx') pipes.push(xlsx.stringify(merge({}, { header: useHeader }, opts)))
104
- if (compress) pipes.push(createGzip())
105
- DataStream.pipeline(stream, ...pipes).pipe(writer)
106
- return getData.call(this, { source, filter, count, stream, progressFn })
107
- })
108
- .then(cnt => {
109
- count = cnt
110
- })
111
- .catch(reject)
112
- })
113
- }
114
-
115
- export default exportTo
@@ -1,70 +0,0 @@
1
- import path from 'path'
2
- import scramjet from 'scramjet'
3
- import format from '../../lib/ndjson-csv-xlsx.js'
4
- import { createGunzip } from 'zlib'
5
-
6
- const { json, ndjson, csv, xlsx } = format
7
- const { DataStream } = scramjet
8
- const supportedExt = ['.json', '.jsonl', '.ndjson', '.csv', '.xlsx', '.tsv']
9
-
10
- async function importFrom (source, dest, { trashOld = true, batch = 1, progressFn, converterFn, useHeader = true, fileType, createOpts = {} } = {}, opts = {}) {
11
- const { error, importPkg, getConfig, getPluginDataDir } = this.bajo.helper
12
- if (dest !== false) {
13
- if (!this.bajoDb) throw error('Bajo DB isn\'t loaded')
14
- await this.bajoDb.helper.getInfo(dest)
15
- }
16
- const { merge } = await importPkg('lodash-es')
17
- const fs = await importPkg('fs-extra')
18
- const cfg = getConfig('bajoExtra')
19
-
20
- let file
21
- if (path.isAbsolute(source)) file = source
22
- else {
23
- file = `${getPluginDataDir('bajoExtra')}/import/${source}`
24
- fs.ensureDirSync(path.dirname(file))
25
- }
26
- if (!fs.existsSync(file)) throw error('Source file \'%s\' doesn\'t exist', file)
27
- let ext = fileType ? `.${fileType}` : path.extname(file)
28
- let decompress = false
29
- if (ext === '.gz') {
30
- ext = path.extname(path.basename(file, '.gz'))
31
- decompress = true
32
- }
33
- if (!supportedExt.includes(ext)) throw error('Unsupported format \'%s\'', ext.slice(1))
34
- if (trashOld && dest !== false) await this.bajoDb.helper.recordClear(dest)
35
- const reader = fs.createReadStream(file)
36
- batch = parseInt(batch) || 100
37
- if (batch > cfg.stream.import.maxBatch) batch = cfg.stream.import.maxBatch
38
- if (batch < 0) batch = 1
39
- let count = 0
40
- const pipes = [reader]
41
- if (decompress) pipes.push(createGunzip())
42
- if (ext === '.json') pipes.push(json.parse(opts))
43
- else if (['.ndjson', '.jsonl'].includes(ext)) pipes.push(ndjson.parse(opts))
44
- else if (ext === '.csv') pipes.push(csv.parse(merge({}, { headers: useHeader }, opts)))
45
- else if (ext === '.tsv') pipes.push(csv.parse(merge({}, { headers: useHeader }, merge({}, opts, { delimiter: '\t' }))))
46
- else if (ext === '.xlsx') pipes.push(xlsx.parse(merge({}, { header: useHeader }, opts)))
47
-
48
- const stream = DataStream.pipeline(...pipes)
49
- let batchNo = 1
50
- const data = []
51
- await stream
52
- .batch(batch)
53
- .map(async items => {
54
- if (items.length === 0) return null
55
- const batchStart = new Date()
56
- for (let item of items) {
57
- count++
58
- item = converterFn ? await converterFn.call(this, item) : item
59
- if (dest !== false) await this.bajoDb.helper.recordCreate(dest, item, createOpts)
60
- else data.push(item)
61
- }
62
- if (progressFn) await progressFn.call(this, { batchNo, data: items, batchStart, batchEnd: new Date() })
63
- batchNo++
64
- })
65
- .run()
66
-
67
- return dest === false ? data : { file, count }
68
- }
69
-
70
- export default importFrom
@@ -1,57 +0,0 @@
1
- import Path from 'path'
2
-
3
- const batch = 100
4
-
5
- function makeProgress (spin) {
6
- return async function ({ batchNo, data, batchStart, batchEnd } = {}) {
7
- const { secToHms } = this.bajo.helper
8
- if (data.length === 0) return
9
- spin.setText('Batch #%d (%s)', batchNo, secToHms(batchEnd.toTime() - batchStart.toTime(), true))
10
- }
11
- }
12
-
13
- async function exportTo ({ path, args }) {
14
- const { importPkg, print, dayjs, getConfig, importModule, spinner } = this.bajo.helper
15
- const { isEmpty, map } = await importPkg('lodash-es')
16
- const [input, select] = await importPkg('bajo-cli:@inquirer/input',
17
- 'bajo-cli:@inquirer/select')
18
- const config = getConfig()
19
- if (!this.bajoDb) return print.fail('Bajo DB isn\'t loaded', { exit: config.tool })
20
- const schemas = map(this.bajoDb.schemas, 'name')
21
- if (isEmpty(schemas)) return print.fail('No schema found!', { exit: config.tool })
22
- let [coll, dest, query] = args
23
- if (isEmpty(coll)) {
24
- coll = await select({
25
- message: print.__('Please choose collection:'),
26
- choices: map(schemas, s => ({ value: s }))
27
- })
28
- }
29
- if (isEmpty(dest)) {
30
- dest = await input({
31
- message: print.__('Please enter destination file:'),
32
- default: `${coll}-${dayjs().format('YYYYMMDD')}.ndjson`,
33
- validate: (item) => !isEmpty(item)
34
- })
35
- }
36
- if (isEmpty(query)) {
37
- query = await input({
38
- message: print.__('Please enter a query (if any):')
39
- })
40
- }
41
- const spin = spinner().start('Exporting...')
42
- const progressFn = makeProgress.call(this, spin)
43
- const cfg = getConfig('bajoDb', { full: true })
44
- const start = await importModule(`${cfg.dir.pkg}/bajo/start.js`)
45
- const { connection } = await this.bajoDb.helper.getInfo(coll)
46
- await start.call(this, connection.name)
47
- try {
48
- const filter = { query }
49
- const result = await this.bajoExtra.helper.exportTo(coll, dest, { filter, batch, progressFn })
50
- spin.succeed('%d records successfully exported to \'%s\'', result.count, Path.resolve(result.file))
51
- } catch (err) {
52
- console.log(err)
53
- spin.fail('Error: %s', err.message, { exit: config.tool })
54
- }
55
- }
56
-
57
- export default exportTo
@@ -1,53 +0,0 @@
1
- import Path from 'path'
2
-
3
- const batch = 100
4
-
5
- function makeProgress (spin) {
6
- const { secToHms } = this.bajo.helper
7
- return async function ({ batchNo, data, batchStart, batchEnd } = {}) {
8
- spin.setText('Batch #%d (%s)', batchNo, secToHms(batchEnd.toTime() - batchStart.toTime(), true))
9
- }
10
- }
11
-
12
- async function importFrom ({ path, args }) {
13
- const { importPkg, print, importModule, getConfig, spinner } = this.bajo.helper
14
- const { isEmpty, map } = await importPkg('lodash-es')
15
- const [input, select, confirm] = await importPkg('bajo-cli:@inquirer/input',
16
- 'bajo-cli:@inquirer/select', 'bajo-cli:@inquirer/confirm')
17
- const config = getConfig()
18
- if (!this.bajoDb) return print.fail('Bajo DB isn\'t loaded', { exit: config.tool })
19
- const schemas = map(this.bajoDb.schemas, 'name')
20
- if (isEmpty(schemas)) return print.fail('No schema found!', { exit: config.tool })
21
- let [dest, coll] = args
22
- if (isEmpty(dest)) {
23
- dest = await input({
24
- message: print.__('Please enter source file:'),
25
- validate: (item) => !isEmpty(item)
26
- })
27
- }
28
- if (isEmpty(coll)) {
29
- coll = await select({
30
- message: print.__('Please choose collection:'),
31
- choices: map(schemas, s => ({ value: s }))
32
- })
33
- }
34
- const answer = await confirm({
35
- message: print.__('You\'re about to replace ALL records with the new ones. Are you really sure?'),
36
- default: false
37
- })
38
- if (!answer) return print.fail('Aborted!', { exit: config.tool })
39
- const spin = spinner({ showCounter: true }).start('Importing...')
40
- const progressFn = makeProgress.call(this, spin)
41
- const cfg = getConfig('bajoDb', { full: true })
42
- const start = await importModule(`${cfg.dir.pkg}/bajo/start.js`)
43
- const { connection } = await this.bajoDb.helper.getInfo(coll)
44
- await start.call(this, connection.name)
45
- try {
46
- const result = await this.bajoExtra.helper.importFrom(dest, coll, { batch, progressFn })
47
- spin.succeed('%d records successfully imported from \'%s\'', result.count, Path.resolve(result.file))
48
- } catch (err) {
49
- spin.fail('Error: %s', err.message, { exit: config.tool })
50
- }
51
- }
52
-
53
- export default importFrom
@@ -1,35 +0,0 @@
1
- // Borrowed from: https://github.com/fanlia/ndjson-csv-xlsx/blob/main/index.js
2
-
3
- import ndjson from 'ndjson'
4
- import csv from 'fast-csv'
5
- import xlsxparse from 'xlsx-parse-stream'
6
- import XLSXWriteStream from '@atomictech/xlsx-write-stream'
7
- import StreamArray from 'stream-json/streamers/StreamArray.js'
8
- import stringer from 'stream-json/Stringer.js'
9
- import disassembler from 'stream-json/Disassembler.js'
10
- import chain from 'stream-chain'
11
-
12
- export default {
13
- ndjson: {
14
- parse: (...args) => ndjson.parse(...args),
15
- stringify: (...args) => ndjson.stringify(...args)
16
- },
17
- csv: {
18
- parse: (...args) => csv.parse(...args),
19
- stringify: (...args) => csv.format(...args)
20
- },
21
- xlsx: {
22
- parse: (...args) => xlsxparse(...args),
23
- stringify: (...args) => new XLSXWriteStream(...args)
24
- },
25
- json: {
26
- parse: (...args) => chain([
27
- StreamArray.withParser(...args),
28
- data => data.value
29
- ]),
30
- stringify: (options, ...args) => chain([
31
- disassembler(),
32
- stringer({ ...options, makeArray: true })
33
- ])
34
- }
35
- }