From 33c34b18f718c8d0191009c2770f87d463d52337 Mon Sep 17 00:00:00 2001 From: Timo Hocker Date: Fri, 21 Feb 2020 11:29:50 +0100 Subject: [PATCH] [no publish] finish dot parser --- snippets/db/dot_parser.js | 116 ++++++++++++++++++++++++++++++-------- snippets/db/index.js | 51 +++++------------ test/index.js | 5 +- 3 files changed, 108 insertions(+), 64 deletions(-) diff --git a/snippets/db/dot_parser.js b/snippets/db/dot_parser.js index 72ea502..32299a8 100644 --- a/snippets/db/dot_parser.js +++ b/snippets/db/dot_parser.js @@ -61,7 +61,7 @@ function get_table_info (str) { columns.push (col); } - return { name, columns }; + return { name, columns, foreign_keys: [] }; } /** @@ -80,32 +80,48 @@ async function get_tables (file) { curr.push (l); if ((/>.*?\]/u).test (l)) { - tables.push (curr.join ('\n')); + const val = curr.join ('\n'); + if (val) + tables.push (get_table_info (val)); curr.splice (0, curr.length); } - const fk = (/(?\S+) -> (?\S+)/u).exec (l); - if (fk) { - const col = fk.groups.col.split (':'); - const ref = fk.groups.ref.split (':'); + get_foreign_key (l, foreign); + } - const foreign_key = { - table: col[0], - column: col[1], - ref_table: ref[0], - ref_column: ref[1] - }; - - foreign.push (foreign_key); + for (const fk of foreign) { + for (let i = 0; i < tables.length; i++) { + if (tables[i].name === fk.table) { + tables[i].foreign_keys.push (fk); + break; + } } } - return { - tables: tables - .filter ((val) => val) - .map ((val) => get_table_info (val)), - foreign_keys: foreign - }; + return tables; +} + +/** + * gets foreign keys from a line + * + * @param {string} line line to check + * @param {Array} foreign_keys array to add to + */ +function get_foreign_key (line, foreign_keys) { + const fk = (/(?\S+) -> (?\S+)/u).exec (line); + if (fk) { + const col = fk.groups.col.split (':'); + const ref = fk.groups.ref.split (':'); + + const foreign_key = { + table: col[0], + column: col[1], + ref_table: ref[0], + ref_column: ref[1] + }; + + foreign_keys.push (foreign_key); + } } /** @@ -124,21 +140,75 @@ function create_table_function (table) { function create_${table.name} (knex) { return knex.schema.createTable ('${table.name}', (table) => { ${table.columns - .map ((col) => `table.${col.type}('${col.name}');`) + .map ((col) => `table.${col.type} ('${col.name}');`) .join ('\n ')} `; const unique = table.columns.filter ((val) => val.unique); if (unique.length > 0) { - func += `\n table.unique(${unique + func += `\n table.unique (${unique .map ((val) => `'${val.name}'`) .join (', ')});\n`; } + if (table.foreign_keys.length > 0) { + func += '\n'; + for (const fk of table.foreign_keys) { + func += ` table.foreign ('${fk.column}') + .references ('${fk.ref_column}') + .inTable ('${fk.ref_table}');\n`; + } + } + func += ` }); }`; return func; } -module.exports = { get_tables, create_table_function }; +/** + * creates the migration function + * + * @param {Array} tables table array + * @returns {string} function + */ +function create_up_function (tables) { + const func = `async function up (knex) { +${tables.map ((val) => ` await create_${val.name} (knex);`) + .join ('\n')} +}`; + return func; +} + +/** + * creates the complete migration file for a graph + * + * @param {string} file_path file to scan + * @returns {Promise} file + */ +async function create_migration (file_path) { + const tables = await get_tables (file_path); + const functions = tables.map ((tab) => create_table_function (tab)); + + const file = `${functions.join ('\n\n')} + +/* + * run migration + * + * @param {any} knex db connection + */ +${create_up_function (tables)} + +/* + * revert migration + * + * @param {any} knex db connection + */ +function down () {} + +module.exports = { up, down } +`; + return file; +} + +module.exports = { get_tables, create_table_function, create_migration }; diff --git a/snippets/db/index.js b/snippets/db/index.js index 45bba7f..fd7f538 100644 --- a/snippets/db/index.js +++ b/snippets/db/index.js @@ -2,9 +2,10 @@ * Copyright (C) Sapphirecode - All Rights Reserved * This file is part of snippeteer which is released under BSD-3-Clause. * See file 'LICENSE' for full license details. - * Created by Timo Hocker , January 2020 + * Created by Timo Hocker , February 2020 */ +/* eslint-disable no-magic-numbers */ /* eslint-disable no-sync */ /* eslint-disable no-console */ @@ -12,6 +13,7 @@ const fs = require ('fs-extra'); const path = require ('path'); +const dot_parser = require ('./dot_parser'); /** * copies the full template to a new folder named after arg[0] @@ -19,24 +21,12 @@ const path = require ('path'); * @param {string} folder folder to run in * @param {Array} args function arguments */ -function run (folder, args) { - const snip_folder_path = [ folder ]; - if (args.length > 0) - snip_folder_path.push (args[0]); - const snip_folder = path.join (...snip_folder_path); - const template = path.join (__dirname, 'template'); - if (!fs.existsSync (snip_folder)) - fs.mkdir (snip_folder); - for (const f of fs.readdirSync (template)) { - fs.copy ( - path.join (template, f), - path.join (snip_folder, f), - { - recursive: true, - filter: (src, dest) => !fs.existsSync (dest) - } - ); - } +async function run (folder, args) { + const graph = path.join (folder, args[0]); + const migration = path.join (folder, args[1]); + + const db_migration = dot_parser.create_migration (graph); + await fs.writeFile (migration, db_migration, 'utf-8'); } /** @@ -49,16 +39,10 @@ function run (folder, args) { function assert (folder, args) { const tests = [ { - f: () => (args.length < 2), - reason: 'too many arguments' - }, - { - f: () => (args.length === 0 || typeof args[0] === 'string'), - reason: 'name is not a string' - }, - { - f: () => (args.length === 0 || (/^[a-z]+$/iu).test (args[0])), - reason: 'name can only contain [a-z]' + f: () => (args.length === 2 + && typeof args[0] === 'string' + && typeof args[1] === 'string'), + reason: 'db [graph] [migration]' }, { f: () => (typeof folder === 'string'), @@ -67,15 +51,6 @@ function assert (folder, args) { { f: () => (fs.existsSync (folder)), reason: 'cwd does not exist (internal error)' - }, - { - f: () => (args.length === 1 || fs.readdirSync (folder).length === 0), - reason: 'folder is not empty' - }, - { - f: () => (args.length === 0 - || !fs.existsSync (path.join (folder, args[0]))), - reason: 'folder already exists' } ]; for (const test of tests) { diff --git a/test/index.js b/test/index.js index 18d281e..d5bfd5a 100644 --- a/test/index.js +++ b/test/index.js @@ -7,8 +7,7 @@ const dot_parser = require ('../snippets/db/dot_parser'); * test */ async function test () { - const data = await dot_parser.get_tables ('db_structure.dot'); - for (const table of data) - console.log (dot_parser.create_table_function (table)); + const data = await dot_parser.create_migration ('db_structure.dot'); + console.log (data); } test ();