feat: format options of csv export, closes #196

This commit is contained in:
Fabio Di Stasio 2023-06-14 19:47:09 +02:00
parent e07e7b736e
commit 3ad1e51f42
3 changed files with 126 additions and 12 deletions

View File

@ -152,6 +152,77 @@
</div>
</template>
</ConfirmModal>
<ConfirmModal
v-if="csvModalRequest"
@confirm="downloadTable('csv', csvModalRequest as string, true)"
@hide="csvModalRequest = false"
>
<template #header>
<div class="d-flex">
<i class="mdi mdi-24px mdi-file-export mr-1" />
<span class="cut-text">{{ t('message.csvExportOptions') }}</span>
</div>
</template>
<template #body>
<div class="columns">
<div class="form-group column col-12 columns col-gapless">
<div class="column col-5">
<label class="form-label cut-text">{{ t('message.csvFieldDelimiter') }}:</label>
</div>
<div class="column col-7">
<input
v-model.number="csvExportOptions.fieldDelimiter"
type="string"
class="form-input"
>
</div>
</div>
<div class="form-group column col-12 columns col-gapless">
<div class="column col-5">
<label class="form-label cut-text">{{ t('message.csvStringDelimiter') }}:</label>
</div>
<div class="column col-7">
<BaseSelect
v-model="csvExportOptions.stringDelimiter"
class="form-select"
:options="[
{value: '', label: t('word.none')},
{value: 'single', label: t('word.singleQuote')},
{value: 'double', label: t('word.doubleQuote')}
]"
/>
</div>
</div>
<div class="form-group column col-12 columns col-gapless">
<div class="column col-5">
<label class="form-label cut-text">{{ t('message.csvLinesTerminator') }}:</label>
</div>
<div class="column col-7">
<textarea
v-model.number="csvExportOptions.linesTerminator"
class="form-input"
:style="'resize: none'"
rows="1"
/>
</div>
</div>
<div class="form-group column col-12 columns col-gapless">
<div class="column col-5">
<label class="form-label">
{{ t('message.csvIncludeHeader') }}
</label>
</div>
<div class="column col-7">
<label class="form-switch d-inline-block" @click.prevent="csvExportOptions.header = !csvExportOptions.header">
<input type="checkbox" :checked="csvExportOptions.header">
<i class="form-icon" />
</label>
</div>
</div>
</div>
</template>
</ConfirmModal>
</div>
</template>
@ -223,11 +294,18 @@ const rowHeight = ref(23);
const selectedField = ref(null);
const isEditingRow = ref(false);
const chunkModalRequest: Ref<false | string> = ref(false);
const csvModalRequest: Ref<false | string> = ref(false);
const sqlExportOptions = ref({
sqlInsertAfter: 250,
sqlInsertDivider: 'bytes' as 'bytes' | 'rows',
targetTable: ''
});
const csvExportOptions = ref({
header: true,
fieldDelimiter: ';',
linesTerminator: '\n',
stringDelimiter: 'double'
});
const workspaceSchema = computed(() => getWorkspace(props.connUid).breadcrumbs.schema);
const workspaceClient = computed(() => getWorkspace(props.connUid).client);
@ -718,10 +796,10 @@ const selectResultset = (index: number) => {
resultsetIndex.value = index;
};
const downloadTable = (format: 'csv' | 'json' | 'sql' | 'php', table: string, chunks = false) => {
const downloadTable = (format: 'csv' | 'json' | 'sql' | 'php', table: string, popup = false) => {
if (!sortedResults.value) return;
if (format === 'sql' && !chunks && customizations.value.exportByChunks) {
if (format === 'sql' && !popup && customizations.value.exportByChunks) {
sqlExportOptions.value = {
sqlInsertAfter: 250,
sqlInsertDivider: 'bytes' as 'bytes' | 'rows',
@ -730,8 +808,20 @@ const downloadTable = (format: 'csv' | 'json' | 'sql' | 'php', table: string, ch
chunkModalRequest.value = table;
return;
}
else
else if (format === 'csv' && !popup) {
csvExportOptions.value = {
header: true,
fieldDelimiter: ';',
linesTerminator: '\\n',
stringDelimiter: 'double'
};
csvModalRequest.value = table;
return;
}
else {
chunkModalRequest.value = false;
csvModalRequest.value = false;
}
const rows = sortedResults.value.map((row: any) => {
const clonedRow = { ...row };
@ -747,7 +837,8 @@ const downloadTable = (format: 'csv' | 'json' | 'sql' | 'php', table: string, ch
},
client: workspaceClient.value,
table,
sqlOptions: chunks ? { ...sqlExportOptions.value }: null
sqlOptions: popup ? { ...sqlExportOptions.value }: null,
csvOptions: popup ? { ...csvExportOptions.value }: null
});
};

View File

@ -150,7 +150,10 @@ export const enUS = {
label: 'Label',
icon: 'Icon',
resultsTable: 'Results table',
ddl: 'DDL'
ddl: 'DDL',
none: 'None',
singleQuote: 'Single quote',
doubleQuote: 'Double quote'
},
message: {
appWelcome: 'Welcome to Antares SQL Client!',
@ -349,7 +352,12 @@ export const enUS = {
closeOtherTabs: 'Close other tabs',
closeTabsToLeft: 'Close tabs to the left',
closeTabsToRight: 'Close tabs to the right',
switchDatabase: 'Switch the database'
switchDatabase: 'Switch the database',
csvExportOptions: 'CSV export options',
csvFieldDelimiter: 'Field delimiter',
csvLinesTerminator: 'Line terminator',
csvStringDelimiter: 'String delimiter',
csvIncludeHeader: 'Include header'
},
faker: {
address: 'Address',

View File

@ -10,7 +10,17 @@ export const exportRows = (args: {
fields?: {
[key: string]: {type: string; datePrecision: number};
};
sqlOptions?: {sqlInsertAfter: number; sqlInsertDivider: 'bytes' | 'rows'; targetTable: string};
sqlOptions?: {
sqlInsertAfter: number;
sqlInsertDivider: 'bytes' | 'rows';
targetTable: string;
};
csvOptions?: {
header: boolean;
fieldDelimiter: string;
linesTerminator: string;
stringDelimiter: string;
};
}) => {
let mime;
let content;
@ -19,20 +29,25 @@ export const exportRows = (args: {
case 'csv': {
mime = 'text/csv';
const csv = [];
const sd = args.csvOptions.stringDelimiter === 'single'
? '\''
: args.csvOptions.stringDelimiter === 'single'
? '"'
: '';
if (args.content.length)
csv.push(Object.keys(args.content[0]).join(';'));
if (args.content.length && args.csvOptions.header)
csv.push(Object.keys(args.content[0]).join(args.csvOptions.fieldDelimiter));
for (const row of args.content) {
csv.push(Object.values(row).map(col => {
if (typeof col === 'string') return `"${col}"`;
if (typeof col === 'string') return `${sd}${col}${sd}`;
if (col instanceof Buffer) return col.toString('base64');
if (col instanceof Uint8Array) return Buffer.from(col).toString('base64');
return col;
}).join(';'));
}).join(args.csvOptions.fieldDelimiter));
}
content = csv.join('\n');
content = csv.join(args.csvOptions.linesTerminator.replaceAll('\\n', '\n').replaceAll('\\r', '\r'));
break;
}
case 'sql': {