diff --git a/packages/api/src/shell/index.js b/packages/api/src/shell/index.js index fe9652579..905c3e6ea 100644 --- a/packages/api/src/shell/index.js +++ b/packages/api/src/shell/index.js @@ -6,6 +6,7 @@ const copyStream = require('./copyStream'); const fakeObjectReader = require('./fakeObjectReader'); const consoleObjectWriter = require('./consoleObjectWriter'); const jsonLinesWriter = require('./jsonLinesWriter'); +const jsonArrayWriter = require('./jsonArrayWriter'); const jsonLinesReader = require('./jsonLinesReader'); const jslDataReader = require('./jslDataReader'); const archiveWriter = require('./archiveWriter'); @@ -26,6 +27,7 @@ const dbgateApi = { tableReader, copyStream, jsonLinesWriter, + jsonArrayWriter, jsonLinesReader, fakeObjectReader, consoleObjectWriter, diff --git a/packages/api/src/shell/jsonArrayWriter.js b/packages/api/src/shell/jsonArrayWriter.js new file mode 100644 index 000000000..db6c5c3de --- /dev/null +++ b/packages/api/src/shell/jsonArrayWriter.js @@ -0,0 +1,51 @@ +const fs = require('fs'); +const stream = require('stream'); + +class StringifyStream extends stream.Transform { + constructor() { + super({ objectMode: true }); + this.wasHeader = false; + this.wasRecord = false; + } + _transform(chunk, encoding, done) { + let skip = false; + + if (!this.wasHeader) { + skip = + chunk.__isStreamHeader || + // TODO remove isArray test + Array.isArray(chunk.columns); + this.wasHeader = true; + } + if (!skip) { + if (!this.wasRecord) { + this.push('[\n'); + } else { + this.push(',\n'); + } + this.wasRecord = true; + + this.push(JSON.stringify(chunk)); + } + done(); + } + + _flush() { + if (!this.wasRecord) { + this.push('[]\n'); + } else { + this.push('\n]\n'); + } + } +} + +async function jsonArrayWriter({ fileName, encoding = 'utf-8' }) { + console.log(`Writing file ${fileName}`); + const stringify = new StringifyStream(); + const fileStream = fs.createWriteStream(fileName, encoding); + stringify.pipe(fileStream); + stringify['finisher'] = fileStream; + return stringify; +} + +module.exports = jsonArrayWriter; diff --git a/packages/web/src/plugins/PluginsProvider.svelte b/packages/web/src/plugins/PluginsProvider.svelte index d0d198290..c6d30dd61 100644 --- a/packages/web/src/plugins/PluginsProvider.svelte +++ b/packages/web/src/plugins/PluginsProvider.svelte @@ -45,14 +45,6 @@ return res; } - function buildQuickExports(plugins) { - const res = []; - for (const { content } of plugins) { - if (content.quickExports) res.push(...content.quickExports); - } - return res; - } - export function buildExtensions(plugins) { const extensions = { plugins, @@ -71,7 +63,7 @@ import { extensions, loadingPluginStore } from '../stores'; import axiosInstance from '../utility/axiosInstance'; import { useInstalledPlugins } from '../utility/metadataLoaders'; - import { buildFileFormats } from './fileformats'; + import { buildFileFormats, buildQuickExports } from './fileformats'; import { buildThemes } from './themes'; import dbgateTools from 'dbgate-tools'; diff --git a/packages/web/src/plugins/fileformats.ts b/packages/web/src/plugins/fileformats.ts index 2f8fddf86..6f91fa086 100644 --- a/packages/web/src/plugins/fileformats.ts +++ b/packages/web/src/plugins/fileformats.ts @@ -1,4 +1,4 @@ -import { FileFormatDefinition } from 'dbgate-types'; +import { FileFormatDefinition, QuickExportDefinition } from 'dbgate-types'; const jsonlFormat = { storageType: 'jsonl', @@ -8,8 +8,37 @@ const jsonlFormat = { writerFunc: 'jsonLinesWriter', }; +const jsonFormat = { + storageType: 'json', + extension: 'json', + name: 'JSON', + writerFunc: 'jsonArrayWriter', +}; + +const jsonlQuickExport = { + label: 'JSON lines', + extension: 'jsonl', + createWriter: fileName => ({ + functionName: 'jsonLinesWriter', + props: { + fileName, + }, + }), +}; + +const jsonQuickExport = { + label: 'JSON', + extension: 'json', + createWriter: fileName => ({ + functionName: 'jsonArrayWriter', + props: { + fileName, + }, + }), +}; + export function buildFileFormats(plugins): FileFormatDefinition[] { - const res = [jsonlFormat]; + const res = [jsonlFormat, jsonFormat]; for (const { content } of plugins) { const { fileFormats } = content; if (fileFormats) res.push(...fileFormats); @@ -17,6 +46,14 @@ export function buildFileFormats(plugins): FileFormatDefinition[] { return res; } +export function buildQuickExports(plugins): QuickExportDefinition[] { + const res = [jsonQuickExport, jsonlQuickExport]; + for (const { content } of plugins) { + if (content.quickExports) res.push(...content.quickExports); + } + return res; +} + export function findFileFormat(extensions, storageType) { return extensions.fileFormats.find(x => x.storageType == storageType); }