|
|
|
import { TemplateGenerator } from 'nocodb-sdk'
|
|
|
|
import { UITypes } from '~/components/project/spreadsheet/helpers/uiTypes'
|
|
|
|
import { getCheckboxValue, isCheckboxType } from '~/components/import/templateParsers/parserHelpers'
|
|
|
|
|
|
|
|
const jsonTypeToUidt = {
|
|
|
|
number: UITypes.Number,
|
|
|
|
string: UITypes.SingleLineText,
|
|
|
|
date: UITypes.DateTime,
|
|
|
|
boolean: UITypes.Checkbox,
|
|
|
|
object: UITypes.LongText
|
|
|
|
}
|
|
|
|
|
|
|
|
export default class JSONTemplateAdapter extends TemplateGenerator {
|
|
|
|
constructor(name = 'test', data, parserConfig = {}) {
|
|
|
|
super()
|
|
|
|
this.config = {
|
|
|
|
maxRowsToParse: 500,
|
|
|
|
...parserConfig
|
|
|
|
}
|
|
|
|
this.name = name
|
|
|
|
this.jsonData = typeof data === 'string' ? JSON.parse(data) : data
|
|
|
|
this.project = {
|
|
|
|
title: this.name,
|
|
|
|
tables: []
|
|
|
|
}
|
|
|
|
this.data = {}
|
|
|
|
}
|
|
|
|
|
|
|
|
async init() {
|
|
|
|
}
|
|
|
|
|
|
|
|
parseData() {
|
|
|
|
this.columns = this.csv.meta.fields
|
|
|
|
this.data = this.csv.data
|
|
|
|
}
|
|
|
|
|
|
|
|
getColumns() {
|
|
|
|
return this.columns
|
|
|
|
}
|
|
|
|
|
|
|
|
getData() {
|
|
|
|
return this.data
|
|
|
|
}
|
|
|
|
|
|
|
|
parse() {
|
|
|
|
const jsonData = Array.isArray(this.this.jsonData) ? this.this.jsonData : [this.jsonData]
|
|
|
|
|
|
|
|
// for (let i = 0; i < this.wb.SheetNames.length; i++) {
|
|
|
|
// const columnNamePrefixRef = { id: 0 }
|
|
|
|
|
|
|
|
const tn = 'table'
|
|
|
|
|
|
|
|
const table = { table_name: tn, ref_table_name: tn, columns: [] }
|
|
|
|
|
|
|
|
this.data[tn] = []
|
|
|
|
|
|
|
|
// const ws = this.wb.Sheets[sheet]
|
|
|
|
// const range = XLSX.utils.decode_range(ws['!ref'])
|
|
|
|
// const rows = XLSX.utils.sheet_to_json(ws, { header: 1, blankrows: false, cellDates: true, defval: null })
|
|
|
|
|
|
|
|
const objKeys = Object.keys(jsonData[0])
|
|
|
|
|
|
|
|
for (let col = 0; col < objKeys.length; col++) {
|
|
|
|
const key = objKeys[col]
|
|
|
|
const cn = objKeys[col].replace(/\W/g, '_').trim()
|
|
|
|
|
|
|
|
const column = {
|
|
|
|
column_name: cn,
|
|
|
|
ref_column_name: cn
|
|
|
|
}
|
|
|
|
|
|
|
|
table.columns.push(column)
|
|
|
|
|
|
|
|
column.uidt = jsonTypeToUidt[typeof jsonData[0][key]] || UITypes.SingleLineText
|
|
|
|
|
|
|
|
// todo: optimize
|
|
|
|
if (column.uidt === UITypes.SingleLineText) {
|
|
|
|
// check for long text
|
|
|
|
if (jsonData.some(r =>
|
|
|
|
(r[key] || '').toString().match(/[\r\n]/) ||
|
|
|
|
(r[key] || '').toString().length > 255)
|
|
|
|
) {
|
|
|
|
column.uidt = UITypes.LongText
|
|
|
|
} else {
|
|
|
|
const vals = jsonData
|
|
|
|
.map(r => r[key])
|
|
|
|
.filter(v => v !== null && v !== undefined && v.toString().trim() !== '')
|
|
|
|
|
|
|
|
const checkboxType = isCheckboxType(vals)
|
|
|
|
if (checkboxType.length === 1) {
|
|
|
|
column.uidt = UITypes.Checkbox
|
|
|
|
} else {
|
|
|
|
// todo: optimize
|
|
|
|
// check column is multi or single select by comparing unique values
|
|
|
|
// todo:
|
|
|
|
// eslint-disable-next-line no-lonely-if
|
|
|
|
if (vals.some(v => v && v.toString().includes(','))) {
|
|
|
|
let flattenedVals = vals.flatMap(v => v ? v.toString().trim().split(/\s*,\s*/) : [])
|
|
|
|
const uniqueVals = flattenedVals = flattenedVals
|
|
|
|
.filter((v, i, arr) => i === arr.findIndex(v1 => v.toLowerCase() === v1.toLowerCase()))
|
|
|
|
if (flattenedVals.length > uniqueVals.length && uniqueVals.length <= Math.ceil(flattenedVals.length / 2)) {
|
|
|
|
column.uidt = UITypes.MultiSelect
|
|
|
|
column.dtxp = `'${uniqueVals.join("','")}'`
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
const uniqueVals = vals.map(v => v.toString().trim()).filter((v, i, arr) => i === arr.findIndex(v1 => v.toLowerCase() === v1.toLowerCase()))
|
|
|
|
if (vals.length > uniqueVals.length && uniqueVals.length <= Math.ceil(vals.length / 2)) {
|
|
|
|
column.uidt = UITypes.SingleSelect
|
|
|
|
column.dtxp = `'${uniqueVals.join("','")}'`
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (column.uidt === UITypes.Number) {
|
|
|
|
if (jsonData.slice(1, this.config.maxRowsToParse).some((v) => {
|
|
|
|
return v && v[key] && parseInt(+v[key]) !== +v[key]
|
|
|
|
})) {
|
|
|
|
column.uidt = UITypes.Decimal
|
|
|
|
}
|
|
|
|
if (jsonData.every((v, i) => {
|
|
|
|
return v[key] && v[key].toString().startsWith('$')
|
|
|
|
})) {
|
|
|
|
column.uidt = UITypes.Currency
|
|
|
|
}
|
|
|
|
} else if (column.uidt === UITypes.DateTime) {
|
|
|
|
if (jsonData.every((v, i) => {
|
|
|
|
return v[key] && v[key].toString().split(' ').length === 1
|
|
|
|
})) {
|
|
|
|
column.uidt = UITypes.Date
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// let rowIndex = 0
|
|
|
|
for (const row of jsonData) {
|
|
|
|
const rowData = {}
|
|
|
|
for (let i = 0; i < table.columns.length; i++) {
|
|
|
|
if (table.columns[i].uidt === UITypes.Checkbox) {
|
|
|
|
rowData[table.columns[i].column_name] = getCheckboxValue(row[i])
|
|
|
|
} else if (table.columns[i].uidt === UITypes.Currency) {
|
|
|
|
rowData[table.columns[i].column_name] = (row[table.columns[i].ref_column_name].replace(/[^\d.]+/g, '')) || row[i]
|
|
|
|
} else if (table.columns[i].uidt === UITypes.SingleSelect || table.columns[i].uidt === UITypes.MultiSelect) {
|
|
|
|
rowData[table.columns[i].column_name] = (row[table.columns[i].ref_column_name] || '').toString().trim() || null
|
|
|
|
} else {
|
|
|
|
// toto: do parsing if necessary based on type
|
|
|
|
rowData[table.columns[i].column_name] = row[table.columns[i].ref_column_name]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.data[tn].push(rowData)
|
|
|
|
// rowIndex++
|
|
|
|
}
|
|
|
|
this.project.tables.push(table)
|
|
|
|
}
|
|
|
|
|
|
|
|
getTemplate() {
|
|
|
|
return this.project
|
|
|
|
}
|
|
|
|
}
|