UNPKG

@naturalcycles/mysql-lib

Version:

MySQL client implementing CommonDB interface

103 lines (102 loc) 3.2 kB
import * as mysql from 'mysql'; /** * It currently skips nullability and declares everything as "DEFAULT NULL". */ export function jsonSchemaToMySQLDDL(table, schema, opt = {}) { const { engine = 'InnoDB' } = opt; const lines = [`CREATE TABLE ${mysql.escapeId(table)} (`]; const innerLines = Object.entries(schema.properties).map(([k, s]) => { if (k === 'id') { return `id VARCHAR(255) NOT NULL`; } let type; if (s.type === 'string') { // can specify isoDate later type = 'LONGTEXT'; } else if (s.type === 'integer') { type = 'INT(11)'; } else if (s.type === 'number') { if (['unixTimestamp', 'int32'].includes(s.format)) { type = 'INT(11)'; } else { type = 'FLOAT(11)'; } } else if (s.type === 'boolean') { type = 'TINYINT(1)'; } else if (s.instanceof === 'Buffer') { type = 'LONGBLOB'; } else if (s.type === 'null') { type = 'VARCHAR(255)'; } else if (s.type === 'array') { type = 'LONGTEXT'; // to be JSON.stringified? } else if (s.type === 'object') { type = 'LONGTEXT'; // to be JSON.stringified? } else { // default type = 'LONGTEXT'; } const tokens = [mysql.escapeId(mapNameToMySQL(k)), type, `DEFAULT NULL`]; return tokens.join(' '); }); innerLines.push(`PRIMARY KEY (id)`); lines.push(innerLines.join(',\n')); lines.push(`) ENGINE=${engine}`); return lines.join('\n'); } export function mysqlTableStatsToJsonSchemaField(table, stats, logger) { const s = { $id: `${table}.schema.json`, type: 'object', properties: {}, required: [], additionalProperties: true, }; stats.forEach(stat => { const name = stat.Field; const t = stat.Type.toLowerCase(); const notNull = stat.Null?.toUpperCase() !== 'YES'; if (notNull) { s.required.push(name); } if (t.includes('text') || t.includes('char')) { s.properties[name] = { type: 'string' }; } else if (t.includes('lob')) { s.properties[name] = { instanceof: 'Buffer' }; } else if (t.startsWith('tinyint') || t.includes('(1)')) { s.properties[name] = { type: 'boolean' }; } else if (t === 'int' || t.startsWith('int(')) { s.properties[name] = { type: 'integer' }; } else if (t.startsWith('float')) { s.properties[name] = { type: 'number' }; } else { logger.log(s); throw new Error(`Unknown mysql field type ${name} ${stat.Type}`); } }); return s; } /** * Because MySQL doesn't support `.` in field names and escapes them as tableName + fieldName. * * @param name */ export function mapNameToMySQL(name) { return name.replaceAll('.', '_dot_'); } export function mapNameFromMySQL(name) { return name.replaceAll('_dot_', '.'); }