mirror of https://github.com/nocodb/nocodb
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
130 lines
4.1 KiB
130 lines
4.1 KiB
import { UITypes } from 'nocodb-sdk' |
|
import { getCheckboxValue, getColumnUIDTAndMetas } from './parserHelpers' |
|
import TemplateGenerator from './TemplateGenerator' |
|
|
|
const jsonTypeToUidt: Record<string, string> = { |
|
number: UITypes.Number, |
|
string: UITypes.SingleLineText, |
|
date: UITypes.DateTime, |
|
boolean: UITypes.Checkbox, |
|
object: UITypes.JSON, |
|
} |
|
|
|
const extractNestedData: any = (obj: any, path: any) => path.reduce((val: any, key: any) => val && val[key], obj) |
|
|
|
export default class JSONTemplateAdapter extends TemplateGenerator { |
|
config: Record<string, any> |
|
data: Record<string, any> |
|
_jsonData: string | Record<string, any> |
|
jsonData: Record<string, any> |
|
project: { |
|
tables: Record<string, any>[] |
|
} |
|
|
|
columns: object |
|
constructor(data: object, parserConfig = {}, progressCallback?: (msg: string) => void) { |
|
super(progressCallback) |
|
this.config = parserConfig |
|
this._jsonData = data |
|
this.project = { |
|
tables: [], |
|
} |
|
this.jsonData = [] |
|
this.data = [] |
|
this.columns = {} |
|
} |
|
|
|
async init() { |
|
this.progress('Initializing json parser') |
|
const parsedJsonData = |
|
typeof this._jsonData === 'string' |
|
? // for json editor |
|
JSON.parse(this._jsonData) |
|
: // for file upload |
|
JSON.parse(new TextDecoder().decode(this._jsonData as BufferSource)) |
|
this.jsonData = Array.isArray(parsedJsonData) ? parsedJsonData : [parsedJsonData] |
|
} |
|
|
|
getColumns(): any { |
|
return this.columns |
|
} |
|
|
|
getData(): any { |
|
return this.data |
|
} |
|
|
|
parse(): any { |
|
this.progress('Parsing json data') |
|
const jsonData = this.jsonData |
|
const tn = 'table' |
|
const table: any = { table_name: tn, ref_table_name: tn, columns: [] } |
|
|
|
this.data[tn] = [] |
|
|
|
for (const col of Object.keys(jsonData[0])) { |
|
const columns = this._parseColumn([col], jsonData) |
|
table.columns.push(...columns) |
|
} |
|
|
|
if (this.config.shouldImportData) { |
|
this._parseTableData(table) |
|
} |
|
|
|
this.project.tables.push(table) |
|
} |
|
|
|
getTemplate() { |
|
return this.project |
|
} |
|
|
|
_parseColumn( |
|
path: any = [], |
|
jsonData = this.jsonData, |
|
firstRowVal = path.reduce((val: any, k: any) => val && val[k], this.jsonData[0]), |
|
): any { |
|
const columns = [] |
|
// parse nested |
|
if (firstRowVal && typeof firstRowVal === 'object' && !Array.isArray(firstRowVal) && this.config.normalizeNested) { |
|
for (const key of Object.keys(firstRowVal)) { |
|
const normalizedNestedColumns = this._parseColumn([...path, key], this.jsonData, firstRowVal[key]) |
|
columns.push(...normalizedNestedColumns) |
|
} |
|
} else { |
|
const cn = path.join('_').replace(/\W/g, '_').trim() |
|
const column: Record<string, any> = { |
|
column_name: cn, |
|
ref_column_name: cn, |
|
uidt: UITypes.SingleLineText, |
|
path, |
|
} |
|
if (this.config.autoSelectFieldTypes) { |
|
column.uidt = jsonTypeToUidt[typeof firstRowVal] || UITypes.SingleLineText |
|
const colData = jsonData.map((r: any) => extractNestedData(r, path)) |
|
Object.assign(column, getColumnUIDTAndMetas(colData, column.uidt)) |
|
} |
|
columns.push(column) |
|
} |
|
|
|
return columns |
|
} |
|
|
|
_parseTableData(tableMeta: any) { |
|
for (const row of this.jsonData as any) { |
|
const rowData: any = {} |
|
for (let i = 0; i < tableMeta.columns.length; i++) { |
|
const value = extractNestedData(row, tableMeta.columns[i].path || []) |
|
if (tableMeta.columns[i].uidt === UITypes.Checkbox) { |
|
rowData[tableMeta.columns[i].ref_column_name] = getCheckboxValue(value) |
|
} else if (tableMeta.columns[i].uidt === UITypes.SingleSelect || tableMeta.columns[i].uidt === UITypes.MultiSelect) { |
|
rowData[tableMeta.columns[i].ref_column_name] = (value || '').toString().trim() || null |
|
} else if (tableMeta.columns[i].uidt === UITypes.JSON) { |
|
rowData[tableMeta.columns[i].ref_column_name] = JSON.stringify(value) |
|
} else { |
|
// toto: do parsing if necessary based on type |
|
rowData[tableMeta.columns[i].column_name] = value |
|
} |
|
} |
|
this.data[tableMeta.ref_table_name].push(rowData) |
|
} |
|
} |
|
}
|
|
|