parse-server-schema-to-dbml
Version:
Convert ParseServer _SCHEMA Mongo collection data to DBML (SQL by dbdiagram.io) to visualise relations between Parse classes
178 lines (132 loc) • 5.04 kB
JavaScript
const { program } = require('commander');
const fs = require('fs');
// Material pallete 700 or 800 or 900 for white text
const colors = {
red: '#d32f2f',
pink: '#c2185b',
purple: '#7b1fa2',
deepPurple: '#512da8',
indigo: '#303f9f',
blue: '#1976d2',
lightBlue: '#0277bd',
cyan: '#00838f',
teal: '#00796b',
green: '#2e7d32',
lightGreen: '#387002',
lime: '#6c6f00',
yellow: '#bc5100',
amber: '#c43e00',
orange: '#bb4d00',
deepOrange: '#ac0800',
brown: '#5d4037',
grey: '#616161',
blueGrey: '#455a64'
}
const colorByIndex = (id) => {
const colorsArray = Object.values(colors);
const index = id % colorsArray.length;
return colorsArray[index];
}
const convert = (schemaJSON, schemaDBML) => {
console.log(`Converting: ${schemaJSON} to ${schemaDBML}`);
// read MongoDB _SCHEMA collection from _SCHEMA.json as JSON array of objects
const _SCHEMA = JSON.parse(fs.readFileSync(schemaJSON, 'utf-8'));
// console.log(_SCHEMA);
let classIndex = 0;
let DBML = [];
DBML.push(`// Generated by parseServerSchema2dbml`);
_SCHEMA.forEach(parseClass => {
const className = parseClass._id;
console.log(className);
const keys = Object.keys(parseClass);
const fields = keys.filter(key => {
// Remove specific Parse keys (keep only custom fields)
if (!['_id', 'objectId', 'updatedAt', 'createdAt', '_metadata'].includes(key)) {
return key;
}
});
const metadata = parseClass['_metadata'];
// console.log(metadata);
const fieldsOptions = metadata['fields_options'] || {};
const color = colorByIndex(classIndex);
let TABLE = `Table ${className} [headercolor: ${color}] {
objectId string
createdAt date [default: \`now()\`, note: "created time"]
updatedAt date [default: \`now()\`, note: "updated time"]
`;
const scalarFields = [];
const pointerFields = [];
const relationFields = [];
const indexes = [];
indexes.push(` objectId [pk]`);
const dbmlOptions = {};
fields.forEach(fieldName => {
const fieldType = parseClass[fieldName];
// console.log(fieldName, fieldType);
const fieldOptions = fieldsOptions[fieldName] || {};
// console.log(fieldName, fieldOptions);
dbmlOptions[fieldName] = [];
if (fieldOptions.defaultValue !== undefined) {
dbmlOptions[fieldName].push(`default: \`${JSON.stringify(fieldOptions.defaultValue)}\``)
}
const notes = [];
if (fieldOptions.required) {
notes.push('required');
}
if (fieldType.startsWith('*')) { // Pointer
pointerFields.push(fieldName);
const pointerClass = fieldType.substring(1); // Extract `*${pointerClass}`
dbmlOptions[fieldName].push(`ref: > ${pointerClass}.objectId`)
notes.push('MANY-to-ONE');
} else if (fieldType.startsWith('relation<')) { // Relation
relationFields.push(fieldName);
const relationClass = fieldType.substring(9, fieldType.length - 1); // Extract `relation<${relationClass}>`
dbmlOptions[fieldName].push(`ref: - ${relationClass}.objectId`)
notes.push('MANY-to-MANY');
} else { // others
scalarFields.push(fieldName);
}
dbmlOptions[fieldName].push(`note: '${notes.join(', ')}'`)
const dbmlOptionsAsString = dbmlOptions[fieldName].length ? `[${dbmlOptions[fieldName].join(', ')}]` : '';
dbmlOptions[fieldName] = dbmlOptionsAsString;
});
scalarFields.forEach(fieldName => {
const fieldType = parseClass[fieldName];
TABLE += ` ${fieldName} ${fieldType} ${dbmlOptions[fieldName]}
`;
});
pointerFields.forEach(fieldName => {
TABLE += ` ${fieldName} "Pointer" ${dbmlOptions[fieldName]}
`;
});
relationFields.forEach(fieldName => {
TABLE += ` ${fieldName} "Relation" ${dbmlOptions[fieldName]}
`;
});
TABLE += `
indexes {
${indexes.join('\n')}
}
`;
TABLE += `}`;
DBML.push(TABLE);
// console.log(fields);
classIndex += 1;
});
const dbml = DBML.join('\n\n')
// console.log(dbml);
fs.writeFileSync(schemaDBML, dbml);
console.log('DONE');
}
// CLI
program.version('0.2.0');
program
.option('-i --input <input>', 'path to the _SCHEMA.json')
.option('-o --output <output>', 'path to the _SCHEMA.dbml')
.action((env) => {
const schemaJSON = env.input || './_SCHEMA.json';
const schemaDBML = env.output || './_SCHEMA.dbml';
// console.log(input, output);
convert(schemaJSON, schemaDBML);
});
program.parse(process.argv);