Browse Source

feat: csv export api

Signed-off-by: Pranav C <pranavxc@gmail.com>
pull/714/head
Pranav C 3 years ago
parent
commit
adcbb4b49b
  1. 36
      packages/nc-gui/components/project/spreadsheet/components/csvExport.vue
  2. 56
      packages/nocodb/src/lib/dataMapper/lib/sql/BaseModelSql.ts
  3. 25
      packages/nocodb/src/lib/noco/meta/NcMetaMgr.ts

36
packages/nc-gui/components/project/spreadsheet/components/csvExport.vue

@ -60,7 +60,7 @@ export default {
cn = col.lk
? col.lk._lcn
: (this.$store.state.meta.metas[tn].columns.find(c => c.pv) ||
this.$store.state.meta.metas[tn].columns.find(c => c.pk))._cn
this.$store.state.meta.metas[tn].columns.find(c => c.pk))._cn
row[col._cn] = r.row[prop] && r.row[prop].map(r => cn && r[cn])
} else if (col.bt || (col.lk && col.lk.type === 'bt')) {
const tn = col.bt ? col.bt.rtn : col.lk.ltn
@ -75,7 +75,7 @@ export default {
cn = col.lk
? col.lk._lcn
: (this.$store.state.meta.metas[tn].columns.find(c => c.pv) ||
this.$store.state.meta.metas[tn].columns.find(c => c.pk) || {})._cn
this.$store.state.meta.metas[tn].columns.find(c => c.pk) || {})._cn
row[col._cn] = r.row[prop] &&
r.row[prop] && cn && r.row[prop][cn]
} else {
@ -100,8 +100,36 @@ export default {
}))
},
async exportCsv() {
const blob = new Blob([Papaparse.unparse(await this.extractCsvData())], { type: 'text/plain;charset=utf-8' })
FileSaver.saveAs(blob, `${this.meta._tn}_exported.csv`)
// const blob = new Blob([Papaparse.unparse(await this.extractCsvData())], { type: 'text/plain;charset=utf-8' })
try {
const data = await this.$store.dispatch('sqlMgr/ActSqlOp', [
{
dbAlias: this.nodes.dbAlias,
env: '_noco'
},
'xcExportAsCsv',
{
query: {},
model_name: this.meta.tn
},
null,
{
responseType: 'blob'
}
])
// const url = window.URL.createObjectURL(new Blob([data], { type: 'application/zip' }))
// const link = document.createElement('a')
// link.href = url
// link.setAttribute('download', 'meta.zip') // or any other extension
// document.body.appendChild(link)
// link.click()
const blob = new Blob([data], { type: 'text/plain;charset=utf-8' })
FileSaver.saveAs(blob, `${this.meta._tn}_exported.csv`)
this.$toast.success('Successfully exported metadata').goAway(3000)
} catch (e) {
this.$toast.error(e.message).goAway(3000)
}
}
}

56
packages/nocodb/src/lib/dataMapper/lib/sql/BaseModelSql.ts

@ -2347,15 +2347,15 @@ class BaseModelSql extends BaseModel {
if (v.bt) {
const prop = `${this.dbModels[v.bt.rtn]._tn}Read`;
obj[prop] = v;
this._nestedPropsModels[v] = this.dbModels[v.bt?.rtn];
this._nestedPropsModels[prop] = this.dbModels[v.bt?.rtn];
} else if (v.hm) {
const prop = `${this.dbModels[v.hm.tn]._tn}List`;
obj[prop] = v;
this._nestedPropsModels[v] = this.dbModels[v.hm?.tn];
this._nestedPropsModels[prop] = this.dbModels[v.hm?.tn];
} else if (v.mm) {
const prop = `${this.dbModels[v.mm.rtn]._tn}MMList`;
obj[prop] = v;
this._nestedPropsModels[v] = this.dbModels[v.bt?.rtn];
this._nestedPropsModels[prop] = this.dbModels[v.mm?.rtn];
}
return obj;
}, {});
@ -2414,7 +2414,7 @@ class BaseModelSql extends BaseModel {
}, []);
}
public async extractCsvData(args) {
public async extractCsvData(args: any = {}) {
const rows = await this.nestedList(args);
const csvRows = [];
@ -2440,26 +2440,54 @@ class BaseModelSql extends BaseModel {
}
}
for (const prop of Object.keys(this.nestedProps)) {
for (const [prop, col] of Object.entries(this.nestedProps)) {
const refModel = this._nestedPropsModels[prop];
if (prop in row) {
const mapPropFn = (alias, colAlias) => {
if (Array.isArray(row[prop])) {
csvRow[prop] = row.map(r =>
csvRow[alias] = row[prop].map(r =>
refModel.serializeCellValue({
value: r[refModel.primaryColAlias],
columnName: refModel.primaryColAlias
value: r[colAlias],
columnName: colAlias
})
);
} else if (row[prop]) {
csvRow[prop] = refModel.serializeCellValue({
value: row[refModel.primaryColAlias],
columnName: refModel.primaryColAlias
csvRow[alias] = refModel.serializeCellValue({
value: row[colAlias],
columnName: colAlias
});
}
};
if (prop in row) {
// todo: optimize
for (const vColumn of this.virtualColumns) {
if (vColumn.lk) {
if (
col.hm &&
vColumn.lk.type === 'hm' &&
col.hm.tn === vColumn.lk.ltn
) {
mapPropFn(col._cn, vColumn.lk._lcn);
} else if (
col.mm &&
vColumn.lk.type === 'mm' &&
col.mm.rtn === vColumn.lk.ltn
) {
mapPropFn(col._cn, vColumn.lk._lcn);
}
if (
col.bt &&
vColumn.lk.type === 'bt' &&
col.bt.rtn === vColumn.lk.ltn
) {
mapPropFn(col._cn, vColumn.lk._lcn);
}
}
}
}
mapPropFn(col._cn, refModel.primaryColAlias);
}
csvRows.push(csvRow);
}
@ -2474,7 +2502,7 @@ class BaseModelSql extends BaseModel {
value: any;
columnName?: string;
}) {
if (!args.column || !args.columnName) {
if (!args.column && !args.columnName) {
return value;
}
const column =

25
packages/nocodb/src/lib/noco/meta/NcMetaMgr.ts

@ -1418,6 +1418,9 @@ export default class NcMetaMgr {
case 'xcVisibilityMetaGet':
result = await this.xcVisibilityMetaGet(args);
break;
case 'xcExportAsCsv':
result = await this.xcExportAsCsv(args, req, res);
break;
case 'xcVisibilityMetaSet':
result = await this.xcVisibilityMetaSet(args);
@ -1867,6 +1870,10 @@ export default class NcMetaMgr {
return res.download(result.filePath);
}
if (typeof result?.cb === 'function') {
return await result.cb();
}
res.json(result);
} catch (e) {
console.log(e);
@ -3937,6 +3944,24 @@ export default class NcMetaMgr {
return { data: { list: procedures } };
}
protected async xcExportAsCsv(args, _req, res) {
const apiBuilder = this.app?.projectBuilders
?.find(pb => pb.id === this.getProjectId(args))
?.apiBuilders?.find(ab => ab.dbAlias === this.getDbAlias(args));
const model = apiBuilder?.xcModels?.[args.args.model_name];
const csvData = await model.extractCsvData(args.args.query || {});
return {
cb: async () => {
res.set({
'Content-Disposition': `attachment; filename="${args.args.model_name}-export.csv"`
});
res.send(csvData);
}
};
}
// @ts-ignore
protected async xcVisibilityMetaGet(args) {
try {

Loading…
Cancel
Save