diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..69a66f6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +Data +Public/data +CSV2SQL.apache2.conf diff --git a/Artbook/logo.svg b/Artbook/logo.svg new file mode 100755 index 0000000..774f308 --- /dev/null +++ b/Artbook/logo.svg @@ -0,0 +1,94 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/Artbook/logo.xcf b/Artbook/logo.xcf new file mode 100755 index 0000000..874cb22 Binary files /dev/null and b/Artbook/logo.xcf differ diff --git a/PHP/CSV2SQL.Secrets.php b/PHP/CSV2SQL.Secrets.php new file mode 100755 index 0000000..0911a93 --- /dev/null +++ b/PHP/CSV2SQL.Secrets.php @@ -0,0 +1,10 @@ + {}; + + this.start = callback => { + + const end = status => csv2sql.is_function(callback) && callback(status); + + if(started){ + end(false); + return false; + }; + started = true; + + tab = csv2sql.settings_get(["mysql_tabulation", "tabulation"]); + + self.add_reserved_words(csv2sql.settings_get("default_mysql_reserved_words"), () => { + self.add_reserved_words(csv2sql.settings_get("mysql_reserved_words"), () => { + end(true); + }); + }); + + return true; + }; + + this.add_reserved_words = (inputs, callback) => { + + let loaded = 0; + const total = (csv2sql.is_array(inputs) ? inputs : csv2sql.is_string(inputs) ? inputs = [inputs] : inputs = []).length, + end = () => ++ loaded == total && csv2sql.is_function(callback) && callback(); + + if(total){ + for(let i = 0; i < total; i ++){ + if(csv2sql.is_array(inputs[i])) + self.add_reserved_words(inputs[i], end); + else if(csv2sql.is_string(inputs[i]) && inputs[i]){ + if(['[', '{'].includes(inputs[i].trim()[0])){ + try{ + self.add_reserved_words(csv2sql.json_decode(inputs[i]), end); + }catch(exception){ + end(); + }; + continue; + }; + if(/^[a-z0-9_]+$/.test(inputs[i])){ + !reserved_words.includes(inputs[i]) && reserved_words.push(inputs[i]); + end(); + continue; + }; + csv2sql.ajax.get(inputs[i], response => { + try{ + self.add_reserved_words(csv2sql.json_decode(response), end); + }catch(exception){ + end(); + }; + }); + }else + end(); + }; + }else{ + loaded --; + end(); + }; + + }; + + const word = this.word = name => reserved_words.includes(name) ? "`" + name + "`" : name; + + this.database_creator = name => ( + "create database if not exists " + word(name) + " character set utf8mb4 collate utf8mb4_general_ci;\n" + + "use " + word(name) + ";" + ); + + this.table_remover = data => tab + tab + "drop table if exists " + word(data.table) + ";"; + + const attributes = attribute => ( + attribute.type == "varchar" ? attribute.length[0] == attribute.length[1] ? "char" : "varchar" : + attribute.type + ) + ( + attribute.type == "varchar" ? "(" + attribute.length[1] + ")" : + "" + ) + (attribute.null ? "" : " not null"); + + this.table_creator = data => { + + let sql = ""; + + data.id_attribute && (sql += "\n" + tab + tab + tab + "id integer not null auto_increment"); + + data.order.forEach(key => { + + const attribute = data.attributes[key]; + + sql += (sql ? "," : "") + "\n" + tab + tab + tab + word(key) + " " + attributes(attribute); + + }); + + data.deleted_attribute && (sql += ",\n" + tab + tab + tab + "deleted datetime"); + data.date_in_attribute && (sql += ",\n" + tab + tab + tab + "date_in datetime not null default now()"); + data.date_out_attribute && (sql += ",\n" + tab + tab + tab + "date_out datetime"); + + data.id_attribute && (sql += ",\n" + tab + tab + tab + "constraint " + csv2sql.to_snake(data.table) + "_id primary key(id)"); + + return tab + tab + "create table if not exists " + word(data.table) + "(" + sql + "\n" + tab + tab + ");" + }; + + this.table_updater = data => { + + let sql = ""; + + data.order.forEach(key => { + + const attribute = data.attributes[key]; + + sql += ((sql ? "\n\n" : "") + + tab + tab + "if (select 1 from information_schema.columns where table_schema = '" + data.database + "' && table_name = '" + data.table + "' && column_name = '" + key + "' limit 1) is null then \n" + + tab + tab + tab + "alter table " + word(data.table) + " add column " + word(key) + " " + attributes(attribute) + ";\n" + + tab + tab + "end if;" + ); + + }); + + data.deleted_attribute && (sql += ("\n\n" + + tab + tab + "if (select 1 from information_schema.columns where table_schema = '" + data.database + "' && table_name = '" + data.table + "' && column_name = 'deleted' limit 1) is null then \n" + + tab + tab + tab + "alter table " + word(data.table) + " add column deleted datetime;\n" + + tab + tab + "end if;" + )); + data.date_in_attribute && (sql += ("\n\n" + + tab + tab + "if (select 1 from information_schema.columns where table_schema = '" + data.database + "' && table_name = '" + data.table + "' && column_name = 'date_in' limit 1) is null then \n" + + tab + tab + tab + "alter table " + word(data.table) + " add column date_in datetime not null default now();\n" + + tab + tab + "end if;" + )); + data.date_out_attribute && (sql += ("\n\n" + + tab + tab + "if (select 1 from information_schema.columns where table_schema = '" + data.database + "' && table_name = '" + data.table + "' && column_name = 'date_out' limit 1) is null then \n" + + tab + tab + tab + "alter table " + word(data.table) + " add column date_out datetime;\n" + + tab + tab + "end if;" + )); + + return sql; + }; + + this.create_filler = data => { + + const header = "insert into " + word(data.table) + "(" + data.order.map(key => word(key)).join(", ") + ") values"; + let sql = ""; + + if(data.uniques.length){}else{ + + data.data.forEach(tuple => { + + let tuple_sql = ""; + + data.order.forEach(key => tuple_sql += (tuple_sql ? ", " : "") + ( + csv2sql.null_or_undefined(tuple[key]) ? "null" : + ["integer", "bigint", "float"].includes(data.attributes[key].type) ? tuple[key] : + ["bool"].includes(data.attributes[key].type) ? tuple[key] ? "true" : "false" : + "'" + tuple[key].replace(/([\\''])/g, "\\$1") + "'" + )); + + sql += (sql ? "," : "") + "\n" + tab + tab + tab + "(" + tuple_sql + ")"; + + }); + + sql = tab + tab + header + sql + ";"; + + }; + + return sql; + }; + + this.create_file = variables => { + + let sql = "", + callers = ""; + const key = variables.key ? variables.key + "_" : ""; + + sql += ( + (variables.creator_database ? variables.creator_database : "use " + word(variables.database) + ";") + "\n\n" + + "delimiter ;^" + ); + + if(variables.remover_tables){ + sql += ("\n\n" + + tab + "drop procedure if exists csv2sql_" + key + "tables_remove;^\n" + + tab + "create procedure csv2sql_" + key + "tables_remove() begin \n\n" + + variables.remover_tables + "\n\n" + + tab + "end;^" + ); + callers += "\n" + tab + "call csv2sql_" + key + "tables_remove();^"; + }; + + if(variables.creator_tables){ + sql += ("\n\n" + + tab + "drop procedure if exists csv2sql_" + key + "tables_create;^\n" + + tab + "create procedure csv2sql_" + key + "tables_create() begin \n\n" + + variables.creator_tables + "\n\n" + + tab + "end;^" + ); + callers += "\n" + tab + "call csv2sql_" + key + "tables_create();^"; + }; + + if(variables.updater_tables){ + sql += ("\n\n" + + tab + "drop procedure if exists csv2sql_" + key + "tables_update;^\n" + + tab + "create procedure csv2sql_" + key + "tables_update() begin \n\n" + + variables.updater_tables + "\n\n" + + tab + "end;^" + ); + callers += "\n" + tab + "call csv2sql_" + key + "tables_update();^"; + }; + + if(variables.filler_tables){ + sql += ("\n\n" + + tab + "drop procedure if exists csv2sql_" + key + "tables_fill;^\n" + + tab + "create procedure csv2sql_" + key + "tables_fill() begin \n\n" + + variables.filler_tables + "\n\n" + + tab + "end;^" + ); + callers += "\n" + tab + "call csv2sql_" + key + "tables_fill();^"; + }; + + callers && (sql += "\n" + callers); + + sql += "\n\ndelimiter ;"; + + return sql; + }; + + construct(); + +}; \ No newline at end of file diff --git a/Public/ecma/CSV2SQL.SQLServer.ecma.js b/Public/ecma/CSV2SQL.SQLServer.ecma.js new file mode 100755 index 0000000..035832c --- /dev/null +++ b/Public/ecma/CSV2SQL.SQLServer.ecma.js @@ -0,0 +1,245 @@ +CSV2SQL.SQLServer = function(csv2sql, input){ + + const self = this, + reserved_words = []; + let started = false, + tab; + + const construct = () => {}; + + this.start = callback => { + + const end = status => csv2sql.is_function(callback) && callback(status); + + if(started){ + end(false); + return false; + }; + started = true; + + tab = csv2sql.settings_get(["mysql_tabulation", "tabulation"]); + + self.add_reserved_words(csv2sql.settings_get("default_sql_server_reserved_words"), () => { + self.add_reserved_words(csv2sql.settings_get("sql_server_reserved_words"), () => { + end(true); + }); + }); + + return true; + }; + + this.add_reserved_words = (inputs, callback) => { + + let loaded = 0; + const total = (csv2sql.is_array(inputs) ? inputs : csv2sql.is_string(inputs) ? inputs = [inputs] : inputs = []).length, + end = () => ++ loaded == total && csv2sql.is_function(callback) && callback(); + + if(total){ + for(let i = 0; i < total; i ++){ + if(csv2sql.is_array(inputs[i])) + self.add_reserved_words(inputs[i], end); + else if(csv2sql.is_string(inputs[i]) && inputs[i]){ + if(['[', '{'].includes(inputs[i].trim()[0])){ + try{ + self.add_reserved_words(csv2sql.json_decode(inputs[i]), end); + }catch(exception){ + end(); + }; + continue; + }; + if(/^[a-z0-9_]+$/.test(inputs[i])){ + !reserved_words.includes(inputs[i]) && reserved_words.push(inputs[i]); + end(); + continue; + }; + csv2sql.ajax.get(inputs[i], response => { + try{ + self.add_reserved_words(csv2sql.json_decode(response), end); + }catch(exception){ + end(); + }; + }); + }else + end(); + }; + }else{ + loaded --; + end(); + }; + + }; + + const word = this.word = name => reserved_words.includes(name) ? "[" + name + "]" : name; + + this.database_creator = name => ( + "if (select top 1 1 from sys.databases where name = '" + name + "') is null create database " + word(name) + "\n" + + "go\n" + + "use " + word(name) + ); + + this.table_remover = data => tab + "if object_id(N'dbo." + data.table + "', N'U') is not null drop table dbo." + word(data.table); + + const attributes = attribute => ( + attribute.type == "varchar" ? attribute.length[0] == attribute.length[1] ? "char" : "varchar" : + attribute.type == "bool" ? "bit" : + attribute.type + ) + ( + attribute.type == "varchar" ? "(" + attribute.length[1] + ")" : + "" + ) + (attribute.null ? "" : " not null"); + + this.table_creator = data => { + + let sql = ""; + + data.id_attribute && (sql += "\n" + tab + tab + "id integer not null identity(1, 1)"); + + data.order.forEach(key => { + + const attribute = data.attributes[key]; + + sql += (sql ? "," : "") + "\n" + tab + tab + word(key) + " " + attributes(attribute); + + }); + + data.deleted_attribute && (sql += ",\n" + tab + tab + "deleted datetime"); + data.date_in_attribute && (sql += ",\n" + tab + tab + "date_in datetime not null constraint " + csv2sql.to_snake(data.table) + "_date_in default getdate()"); + data.date_out_attribute && (sql += ",\n" + tab + tab + "date_out datetime"); + + data.id_attribute && (sql += ",\n" + tab + tab + "constraint " + csv2sql.to_snake(data.table) + "_id primary key(id)"); + + return tab + "if object_id(N'dbo." + data.table + "', N'U') is null create table dbo." + word(data.table) + "(" + sql + "\n" + tab + ")" + }; + + this.table_updater = data => { + + let sql = ""; + + data.order.forEach(key => { + + const attribute = data.attributes[key]; + + sql += ((sql ? "\n\n" : "") + + tab + "if (select top 1 1 from information_schema.columns where table_catalog = '" + data.database + "' and table_name = '" + data.table + "' and column_name = '" + key + "') is null \n" + + tab + tab + "alter table " + word(data.table) + " add " + word(key) + " " + attributes(attribute) + ); + + }); + + data.deleted_attribute && (sql += ("\n\n" + + tab + "if (select top 1 1 from information_schema.columns where table_catalog = '" + data.database + "' and table_name = '" + data.table + "' and column_name = 'deleted') is null \n" + + tab + tab + "alter table " + word(data.table) + " add deleted datetime" + )); + data.date_in_attribute && (sql += ("\n\n" + + tab + "if (select top 1 1 from information_schema.columns where table_catalog = '" + data.database + "' and table_name = '" + data.table + "' and column_name = 'date_in') is null \n" + + tab + tab + "alter table " + word(data.table) + " add date_in datetime not null constraint " + csv2sql.to_snake(data.table) + "_date_in default getdate()" + )); + data.date_out_attribute && (sql += ("\n\n" + + tab + "if (select top 1 1 from information_schema.columns where table_catalog = '" + data.database + "' and table_name = '" + data.table + "' and column_name = 'date_out') is null \n" + + tab + tab + "alter table " + word(data.table) + " add date_out datetime" + )); + + return sql; + }; + + this.create_filler = data => { + + const header = "insert into dbo." + word(data.table) + "(" + data.order.map(key => word(key)).join(", ") + ") values"; + let sql = ""; + + if(data.uniques.length){}else{ + + let subsql = ""; + const division = csv2sql.settings_get("sql_server_insert_division"); + + data.data.forEach((tuple, i) => { + + let tuple_sql = ""; + + if(!(i % division)){ + subsql && (sql += (sql ? "\n" : "") + tab + header + subsql); + subsql = ""; + }; + + data.order.forEach(key => tuple_sql += (tuple_sql ? ", " : "") + ( + tuple[key] === null ? "null" : + ["integer", "bigint", "float"].includes(data.attributes[key].type) ? tuple[key] : + ["bool"].includes(data.attributes[key].type) ? tuple[key] ? "1" : "0" : + "'" + tuple[key].replace(/'/, "''") + "'" + )); + + subsql += (subsql ? "," : "") + "\n" + tab + tab + "(" + tuple_sql + ")"; + + }); + + subsql && (sql += (sql ? "\n" : "") + tab + header + subsql); + + }; + + return sql; + }; + + this.create_file = variables => { + + let sql = "", + callers = ""; + const key = variables.key ? variables.key + "_" : ""; + + sql += variables.creator_database ? variables.creator_database : "use " + word(variables.database); + + if(variables.remover_tables){ + sql += ("\n\n" + + "if object_id(N'dbo.csv2sql_" + key + "tables_remove', N'P') is not null drop procedure dbo.csv2sql_" + key + "tables_remove\n" + + "go\n" + + "create procedure dbo.csv2sql_" + key + "tables_remove as begin \n\n" + + variables.remover_tables + "\n\n" + + "end\n" + + "go" + ); + callers += "\nexecute dbo.csv2sql_" + key + "tables_remove"; + }; + + if(variables.creator_tables){ + sql += ("\n\n" + + "if object_id(N'dbo.csv2sql_" + key + "tables_create', N'P') is not null drop procedure dbo.csv2sql_" + key + "tables_create\n" + + "go\n" + + "create procedure dbo.csv2sql_" + key + "tables_create as begin \n\n" + + variables.creator_tables + "\n\n" + + "end\n" + + "go" + ); + callers += "\nexecute dbo.csv2sql_" + key + "tables_create"; + }; + + if(variables.updater_tables){ + sql += ("\n\n" + + "if object_id(N'dbo.csv2sql_" + key + "tables_update', N'P') is not null drop procedure dbo.csv2sql_" + key + "tables_update\n" + + "go\n" + + "create procedure dbo.csv2sql_" + key + "tables_update as begin \n\n" + + variables.updater_tables + "\n\n" + + "end\n" + + "go" + ); + callers += "\nexecute dbo.csv2sql_" + key + "tables_update"; + }; + + if(variables.filler_tables){ + sql += ("\n\n" + + "if object_id(N'dbo.csv2sql_" + key + "tables_fill', N'P') is not null drop procedure dbo.csv2sql_" + key + "tables_fill\n" + + "go\n" + + "create procedure dbo.csv2sql_" + key + "tables_fill as begin \n\n" + + variables.filler_tables + "\n\n" + + "end\n" + + "go" + ); + callers += "\nexecute dbo.csv2sql_" + key + "tables_fill"; + }; + + callers && (sql += "\n" + callers); + + return sql; + }; + + construct(); + +}; \ No newline at end of file diff --git a/Public/ecma/CSV2SQL.ecma.js b/Public/ecma/CSV2SQL.ecma.js new file mode 100755 index 0000000..cb68a0d --- /dev/null +++ b/Public/ecma/CSV2SQL.ecma.js @@ -0,0 +1,429 @@ +CSV2SQL = function(anp, input){ + + const self = this; + let started = false; + + let mysql = this.mysql; + let sql_server = this.sql_server; + + const construct = () => { + + CSV2SQL.MySQL && (mysql = self.mysql = new CSV2SQL.MySQL(self, input)); + CSV2SQL.SQLServer && (sql_server = self.sql_server = new CSV2SQL.SQLServer(self, input)); + + }; + + this.start = callback => { + + const end = status => csv2sql.is_function(callback) && callback(status); + + if(started){ + end(false); + return; + }; + started = true; + + self.launch(self, ["mysql", "sql_server"], () => { + end(true); + }); + + return true; + }; + + this.create_subforms = item => { + + const default_database = self.item_self.querySelector("[name=default_database]").value, + creator_database = self.item_self.querySelector("[name=default_creator_database]").checked, + remover_tables = self.item_self.querySelector("[name=default_remover_tables]").checked, + creator_tables = self.item_self.querySelector("[name=default_creator_tables]").checked, + updater_tables = self.item_self.querySelector("[name=default_updater_tables]").checked, + filler_tables = self.item_self.querySelector("[name=default_filler_tables]").checked, + uniques = self.item_self.querySelector("[name=default_uniques]").value, + id_attribute = self.item_self.querySelector("[name=default_id_attribute]").checked, + deleted_attribute = self.item_self.querySelector("[name=default_deleted_attribute]").checked, + date_in_attribute = self.item_self.querySelector("[name=default_date_in_attribute]").checked, + date_out_attribute = self.item_self.querySelector("[name=default_date_out_attribute]").checked, + fill_last_attribute = self.item_self.querySelector("[name=default_fill_last_attribute]").checked, + files = self.comp.files.get(item), + container = self.item_self.querySelector(".field[data-i18n=files_data] .content"); + + (self.comp.files.get(item) || []).forEach((file, i) => { + + if(file){ + + if(container.querySelector("[data-i='" + i + "']")) + return; + + const block = container.appendChild(document.createElement("div")); + let html; + + block.innerHTML = html = self.comp.forms.create({ + i18n : "file_data", + variables : { + i : i, + mime : file.mime, + name : file.name, + size : file.size + }, + structure : [ + {name : "database", type : "text", value : default_database}, + {name : "table", type : "text", value : (file.name[0].toUpperCase() + file.name.replace(/\.csv$/i, "").substr(1)).replace(/[^a-z0-9]+([a-z])?/gi, (...arguments) => (arguments[1] || "").toUpperCase())}, + {name : "creator_database", type : "checkbox", checked : creator_database}, + {name : "remover_tables", type : "checkbox", checked : remover_tables}, + {name : "creator_tables", type : "checkbox", checked : creator_tables}, + {name : "updater_tables", type : "checkbox", checked : updater_tables}, + {name : "filler_tables", type : "checkbox", checked : filler_tables}, + {name : "uniques", type : "text", value : uniques, multiline : true}, + {name : "id_attribute", type : "checkbox", checked : id_attribute}, + {name : "deleted_attribute", type : "checkbox", checked : deleted_attribute}, + {name : "date_in_attribute", type : "checkbox", checked : date_in_attribute}, + {name : "date_out_attribute", type : "checkbox", checked : date_out_attribute}, + {name : "fill_last_attribute", type : "checkbox", checked : fill_last_attribute} + ] + }); + block.setAttribute("data-i", i); + + }else{ + + const subform = container.querySelector("[data-i='" + i + "']"); + + subform && subform.remove(); + + }; + + }); + + }; + + const get_files_data = values => { + + const data = [], + default_database = csv2sql.item_self.querySelector("[name=default_database]").value; + + values.files.forEach((file, i) => { + if(!file) + return; + + const subform = csv2sql.item_self.querySelector(".field[data-i18n=files_data] .content [data-i='" + i + "']"), + fill_last_attribute = subform.querySelector("[name=fill_last_attribute]").checked; + + if(!subform) + return; + + const table = [], + tuples = csv2sql.utf8_decode(csv2sql.base64_decode(file.data)).split(/[\r\n]+/), + attributes = {}, + order = []; + let subdata = {}; + + tuples[0].replace(/(^|,)(\s*"([^"]+)"|([^,]+))?/gm, (...arguments) => { + + const name = arguments[3] || arguments[4] || ""; + + order.push(name); + attributes[name] = { + null : false, + type : "unknown", + length : [Number.MAX_SAFE_INTEGER, 0] + }; + + }); + + tuples.slice(1).forEach((tuple, k) => { + if(!tuple) + return; + + let j = 0; + + table.push({}); + + tuple.replace(/(^|,)(\s*"([^"]+)"|([^,]+))?/gm, (...arguments) => { + + let value = arguments[3] || arguments[4] || "", + name = order[j]; + const length = value.length, + type = ( + value == "NULL" ? "null" : + /^[0-9]+$/.test(value) && value.length < 13 ? "integer" : + /^[0-9]+$/.test(value) && value.length < 19 ? "bigint" : + /^(([0-9]+)?\.[0-9]+|[0-9]+\.)$/.test(value) && value.length < 18 ? "float" : + /^(true|false)$/i.test(value) ? "boolean" : + "varchar" + ), + is_null = value == "NULL"; + + if(!name){ + if(fill_last_attribute){ + name = order[order.length - 1]; + value = table[k][name] + "," + value; + }else{ + order.push(name = "column_" + j); + attributes[name] = { + type : "unknown", + length : [Number.MAX_SAFE_INTEGER, 0] + }; + // console.log([k, name, value]); + }; + }; + + if(!is_null){ + length < attributes[name].length[0] && (attributes[name].length[0] = length); + length > attributes[name].length[1] && (attributes[name].length[1] = length); + }; + + is_null && !attributes[name].null && (attributes[name].null = true); + + switch(attributes[name].type){ + case "unknown": + type != "null" && (attributes[name].type = type); + break; + case "integer": + ["float", "varchar"].includes(type) && (attributes[name].type = type); + break; + case "float": + case "boolean": + ["varchar"].includes(type) && (attributes[name].type = type); + break; + }; + + table[k][name] = value == "NULL" ? null : value; + + j ++; + + }); + + }); + + subdata = { + database : subform.querySelector("[name=database]").value || default_database, + table : subform.querySelector("[name=table]").value, + file_name : file.name, + data : table, + attributes : attributes, + order : order, + creator_database : values.files_data[i].creator_database, + uniques : (values.uniques + " " + values.files_data[i].uniques).trim() + }; + subdata.uniques = subdata.uniques ? subdata.uniques.split(/(\s|[\r\n])+/) : []; + + [ + "creator_database", "remover_tables", "creator_tables", + "updater_tables", "filler_tables", "id_attribute", + "deleted_attribute", "date_in_attribute", "date_out_attribute" + ].forEach(key => subdata[key] = values.files_data[i][key]); + + data.push(subdata); + + }); + + return data; + }; + + this.validate_string = (string, empty) => ( + string === undefined ? 1 << 0 : + string === null ? 1 << 1 : + !csv2sql.is_string(string) ? 1 << 2 : + !empty && !string ? 1 << 3 : + 0); + + this.validate_string_messages = key => [ + key + "_undefined", + key + "_null", + key + "_not_string", + key + "_empty" + ]; + + this.validate_files = (files, empty) => ( + files === undefined ? 1 << 0 : + files === null ? 1 << 1 : + !csv2sql.is_array(files) ? 1 << 2 : + !empty && !files.length ? 1 << 3 : + 0); + + this.validate_files_messages = key => [ + key + "_undefined", + key + "_null", + key + "_not_files", + key + "_empty" + ]; + + this.validate_bool = value => ( + value === undefined ? 1 << 0 : + value === null ? 1 << 1 : + !csv2sql.is_bool(value) ? 1 << 2 : + 0); + + this.validate_bool_messages = key => [ + key + "_undefined", + key + "_null", + key + "_not_bool" + ]; + + const validate = (values, conditions) => { + + const messages = ["exception"]; + let error = "", + i = 1, + ok; + + try{ + + conditions.forEach(([key, type, empty, extra]) => { + + const new_messages = self["validate_" + type + "_messages"](key), + new_error = self["validate_" + type](values[key], empty); + + error = csv2sql.errors.set(error, new_error, i, 0); + [].push.apply(messages, new_messages); + + i += new_messages.length; + + !new_error && extra && extra.forEach(([invalid, message]) => { + error = csv2sql.errors.set(error, invalid ? 1 << 0 : 0, i ++, 0); + messages.push(message); + }); + + }); + + }catch(exception){ + csv2sql.settings_get("process_exception_print") && console.error(exception); + ok = false; + error = csv2sql.errors.set(error, 1 << 0, 0, 0); + }; + + return [ok, error, messages]; + }; + + const process = item => { + + const [values, form] = csv2sql.comp.forms.get_values(item); + let [ok, error, messages] = validate(values, [ + ["default_database", "string", true], + ["type", "string", false, [ + [!["mysql", "sqlserver"].includes(values.type), "type_unkown"] + ]], + ["default_creator_database", "bool"], + ["default_remover_tables", "bool"], + ["default_creator_tables", "bool"], + ["default_updater_tables", "bool"], + ["default_filler_tables", "bool"], + ["default_uniques", "string", true], + ["default_id_attribute", "bool"], + ["default_deleted_attribute", "bool"], + ["default_date_in_attribute", "bool"], + ["default_date_out_attribute", "bool"], + ["default_fill_last_attribute", "bool"], + ["files", "files", false], + ["file_name", "string", true] + ]); + + if(ok = csv2sql.errors.validate(form, error, "main_menu_error", messages)){ + + values.files_data = {}; + + form.querySelectorAll(".field[data-i18n=files_data] .structure").forEach(structure => { + + const i_key = structure.parentNode.parentNode.getAttribute("data-i"), + [subvalues, subform] = csv2sql.comp.forms.get_values(structure, true); + let [subok, suberror, submessages] = validate(values, [ + ["database", "string", true, [ + [!values.default_database && !subvalues.database, "database_name_required"] + ]], + ["table", "string", false], + ["creator_database", "bool"], + ["remover_tables", "bool"], + ["creator_tables", "bool"], + ["updater_tables", "bool"], + ["filler_tables", "bool"], + ["uniques", "string", true], + ["id_attribute", "bool"], + ["deleted_attribute", "bool"], + ["date_in_attribute", "bool"], + ["date_out_attribute", "bool"], + ["fill_last_attribute", "bool"] + ]); + + subok = csv2sql.errors.validate(structure.parentNode, suberror, "file_menu_error", submessages, null, {file_name : values.files[i_key].name}); + + !subok && (ok = false); + + values.files_data[i_key] = subvalues; + + }); + + }; + + return [ok, values, form]; + }; + + this.download_files = (item, event) => { + + const [ok, values, form] = process(item); + + if(ok){ + + const zip = new JSZip(), + engine = self[values.type == "mysql" ? "mysql" : "sql_server"]; + + get_files_data(values).forEach(file => { + + zip.file(file.file_name.replace(/\.csv$/i, "." + (values.type == "mysql" ? "my" : "transact") + ".sql"), engine.create_file({ + database : file.database, + creator_database : file.creator_database ? engine.database_creator(file.database) : null, + remover_tables : file.remover_tables ? engine.table_remover(file) : null, + creator_tables : file.creator_tables ? engine.table_creator(file) : null, + updater_tables : file.updater_tables ? engine.table_updater(file) : null, + filler_tables : file.filler_tables ? engine.create_filler(file) : null, + key : self.to_snake(file.table) + })); + + }); + + console.log([values, get_files_data(values)]); + + // self.jszip_download(zip, values.file_name + ".zip"); + + }; + + }; + + this.download_one_file = (item, event) => { + + const [ok, values, form] = process(item); + + if(ok){ + + const engine = self[values.type == "mysql" ? "mysql" : "sql_server"]; + let creator = "", + remover = "", + updater = "", + filler = ""; + + get_files_data(values).forEach(file => { + file.remover_tables && (remover += (remover ? "\n" : "") + engine.table_remover(file)); + file.creator_tables && (creator += (creator ? "\n\n" : "") + engine.table_creator(file)); + file.updater_tables && (updater += (updater ? "\n\n" : "") + engine.table_updater(file)); + file.filler_tables && (filler += (filler ? "\n\n" : "") + engine.create_filler(file)); + }); + + self.download(engine.create_file({ + database : values.default_database, + creator_database : values.default_creator_database ? engine.database_creator(values.default_database) : null, + remover_tables : remover || null, + creator_tables : creator || null, + updater_tables : updater || null, + filler_tables : filler || null + }), "text/plain", values.file_name + "." + (values.type == "mysql" ? "my" : "transact") + ".sql"); + + }; + + }; + + this.to_snake = string => string.replace(/[^a-zA-Z0-9]+([a-zA-Z0-9])|([A-Z0-9]+)/g, (...arguments) => ( + arguments[1] ? "_" + arguments[1] : + "_" + arguments[2] + )).toLowerCase().replace(/^_+|_+$/g, ""); + + construct(); + +}; \ No newline at end of file diff --git a/Public/images/CSV2SQL-180.webp b/Public/images/CSV2SQL-180.webp new file mode 100755 index 0000000..c6761af Binary files /dev/null and b/Public/images/CSV2SQL-180.webp differ diff --git a/Public/images/CSV2SQL-192.webp b/Public/images/CSV2SQL-192.webp new file mode 100755 index 0000000..2ab941f Binary files /dev/null and b/Public/images/CSV2SQL-192.webp differ diff --git a/Public/images/CSV2SQL-270.webp b/Public/images/CSV2SQL-270.webp new file mode 100755 index 0000000..92b367c Binary files /dev/null and b/Public/images/CSV2SQL-270.webp differ diff --git a/Public/images/CSV2SQL-32.webp b/Public/images/CSV2SQL-32.webp new file mode 100755 index 0000000..79a0af2 Binary files /dev/null and b/Public/images/CSV2SQL-32.webp differ diff --git a/Public/images/CSV2SQL-512.webp b/Public/images/CSV2SQL-512.webp new file mode 100755 index 0000000..49ccd0e Binary files /dev/null and b/Public/images/CSV2SQL-512.webp differ diff --git a/Public/images/CSV2SQL.webp b/Public/images/CSV2SQL.webp new file mode 100755 index 0000000..49ccd0e Binary files /dev/null and b/Public/images/CSV2SQL.webp differ diff --git a/Public/images/logo-180.png b/Public/images/logo-180.png new file mode 100755 index 0000000..c5301f3 Binary files /dev/null and b/Public/images/logo-180.png differ diff --git a/Public/images/logo-192.png b/Public/images/logo-192.png new file mode 100755 index 0000000..fdbe153 Binary files /dev/null and b/Public/images/logo-192.png differ diff --git a/Public/images/logo-270.png b/Public/images/logo-270.png new file mode 100755 index 0000000..432fb24 Binary files /dev/null and b/Public/images/logo-270.png differ diff --git a/Public/images/logo-32.png b/Public/images/logo-32.png new file mode 100755 index 0000000..f18ec39 Binary files /dev/null and b/Public/images/logo-32.png differ diff --git a/Public/images/logo-512.png b/Public/images/logo-512.png new file mode 100755 index 0000000..aa9f356 Binary files /dev/null and b/Public/images/logo-512.png differ diff --git a/Public/images/logo.png b/Public/images/logo.png new file mode 100755 index 0000000..c1b97e7 Binary files /dev/null and b/Public/images/logo.png differ diff --git a/Public/index.php b/Public/index.php new file mode 100755 index 0000000..914e977 --- /dev/null +++ b/Public/index.php @@ -0,0 +1,103 @@ + "CSV2SQL", + "language" => "es", + "language_code" => "es_ES", + "license_text" => "© 2022-2023 CopyLeft. GPLv3", + "url" => AnPBuilder::get_host(), + "description" => "Aplicación Web orientada a migrar ficheros CSV a SQL.", + "keywords" => "csv,sql,mariadb,sqlserver,transact,mysql", + "since" => 20230209, + "version" => 20230209, + "kstats" => "1fGQBj6KGMzua8u9zasfhWTmU2jbjuJpCWwCBJvkzhWTnXFipxHZyAu3V", + "extension" => "webp", + "key" => "csv2sql", + "root" => "/^(\\/(index\\.php)?)?\\/?$/", + "domain" => preg_replace('/^csv2sql\.(.+)$/', "$1", $_SERVER["HTTP_HOST"]), + "script" => AnPBuilder::get_cache(function(){ ?> function(){ + + foreach([] as $file) + if(file_exists($file)) + include $file; + + $csv2sql = new AnP([ + "root_paths" => [ + "/mnt/d/git/CSV2SQL", + "/mnt/d/git/CSV2SQL/Public", + "/mnt/d/git/AnP", + "/mnt/d/git/AnP/Public" + ], + "settings_files" => "/JSON/CSV2SQL.php.settings.json", + "routes_files" => "/JSON/CSV2SQL.php.routes.json", + "routes_root" => "/app", + "secrets" => [ + class_exists('\AnP\Secrets') && property_exists('\AnP\Secrets', "settings") ? \AnP\Secrets::settings : [], + class_exists('\CSV2SQL\Secrets') && property_exists('\CSV2SQL\Secrets', "settings") ? \CSV2SQL\Secrets::settings : [], + ] + ]); + + } + ]); diff --git a/Public/json/CSV2SQL.i18n.english.json b/Public/json/CSV2SQL.i18n.english.json new file mode 100755 index 0000000..307d1cf --- /dev/null +++ b/Public/json/CSV2SQL.i18n.english.json @@ -0,0 +1,153 @@ +{ + "english" : { + "files_csv" : "CSV files", + "files_csv_text" : [ + "For convert the CSV files to SQL, please, fill in the next form ", + "and select your local CSV files, and then fill in their subforms." + ], + "default_database" : "The default database", + "default_database_description" : [ + "Choose a default database name for files that not set their own ", + "database." + ], + "type" : "Type", + "type_description" : "Choose the SQL type.", + "default_creator_database" : "Database creator", + "default_creator_database_description" : [ + "Check it if you want create the Database in each SQL archive if ", + "it is not exists by default." + ], + "default_remover_tables" : "Tables remover", + "default_remover_tables_description" : [ + "Check it if you want a tables remover for each CSV file by ", + "default." + ], + "default_creator_tables" : "Tables creator", + "default_creator_tables_description" : [ + "Check it if you want a tables creator for each CSV file by ", + "default." + ], + "default_updater_tables" : "Tables updater", + "default_updater_tables_description" : [ + "Check it if you want a tables attributes updater for each CSV ", + "file by default." + ], + "default_filler_tables" : "Tables filler", + "default_filler_tables_description" : [ + "Check it if you want a tables filler for each CSV file by ", + "default. If you don't check it, any data will be migrated." + ], + "default_uniques" : "Default uniques attributes", + "default_uniques_description" : [ + "In this text box, please, write all default attributes names ", + "that will not be repeated where saving the data separated by a ", + "white space (space, tabulation, new line, etc). If you empty ", + "this field, all data will be saved." + ], + "default_id_attribute" : "ID attribute", + "default_id_attribute_description" : [ + "Check it if you want create the ID auto increment attribute for ", + "each table." + ], + "default_deleted_attribute" : "Deleted attribute", + "default_deleted_attribute_description" : [ + "Check it if you want create the 'deleted' datetime attribute for ", + "each table for detecting a logical user delete." + ], + "default_date_in_attribute" : "Date in attribute", + "default_date_in_attribute_description" : [ + "Check it if you want create the 'date_in' datetime attribute for ", + "each table for registering when was created each register." + ], + "default_date_out_attribute" : "Date out attribute", + "default_date_out_attribute_description" : [ + "Check it if you want create the 'date_out' datetime attribute ", + "for each table for detecting a logical administrator delete." + ], + "default_fill_last_attribute" : "Fill the last attribute", + "default_fill_last_attribute_description" : [ + "Check it if you want fill with unkown columns into last known ", + "attribute by default." + ], + "files" : "Files", + "files_description" : [ + "Select the CSV files that you want convert to SQL." + ], + "files_data" : "Files data", + "files_data_description" : [ + "Here you will have all subforms for each file that you load here." + ], + "database" : "Database", + "database_description" : "Database name for this table.", + "table" : "Table", + "table_description" : "The table name into database.", + "creator_database" : "Database creator", + "creator_database_description" : [ + "Check it if you want create the Database for this file if it is ", + "not exists." + ], + "remover_tables" : "Tables remover", + "remover_tables_description" : [ + "Check it if you want a table remover for this CSV file." + ], + "creator_tables" : "Tables creator", + "creator_tables_description" : [ + "Check it if you want a table creator for this CSV file." + ], + "updater_tables" : "Tables updater", + "updater_tables_description" : [ + "Check it if you want a table attributes updater for this CSV ", + "file." + ], + "filler_tables" : "Tables filler", + "filler_tables_description" : [ + "Check it if you want a tables filler for this CSV file. If you ", + "don't check it, any data will be migrated." + ], + "uniques" : "Uniques attributes", + "uniques_description" : [ + "In this text box, please, write all default attributes names ", + "that will not be repeated where saving the data separated by a ", + "white space (space, tabulation, new line, etc). If you empty ", + "this field, all data will be saved." + ], + "id_attribute" : "ID attribute", + "id_attribute_description" : [ + "Check it if you want create the ID auto increment attribute." + ], + "deleted_attribute" : "Deleted attribute", + "deleted_attribute_description" : [ + "Check it if you want create the 'deleted' datetime attribute for ", + "detecting a logical user delete." + ], + "date_in_attribute" : "Date in attribute", + "date_in_attribute_description" : [ + "Check it if you want create the 'date_in' datetime attribute for ", + "registering when was created each register." + ], + "date_out_attribute" : "Date out attribute", + "date_out_attribute_description" : [ + "Check it if you want create the 'date_out' datetime attribute ", + "for detecting a logical administrator delete." + ], + "fill_last_attribute" : "Fill the last attribute", + "fill_last_attribute_description" : [ + "Check it if you want fill with unkown columns into last known ", + "attribute." + ], + "file_data" : "{name}", + "file_data_text" : "Data for the '{name}' file.", + "file_name" : "File name", + "file_name_description" : "The result file name for saving it.", + "download_files" : "Save files (ZIP)", + "download_one_file" : "Save all in one file", + "main_menu_error" : [ + "There was any error with code '{code}' while getting and ", + "validating the main form data.{list}" + ], + "file_menu_error" : [ + "There was any error with code '{code}' while getting and ", + "validating the file '{file_name}' data.{list}" + ] + } +} \ No newline at end of file diff --git a/Public/json/CSV2SQL.i18n.espanol.json b/Public/json/CSV2SQL.i18n.espanol.json new file mode 100755 index 0000000..17be9e2 --- /dev/null +++ b/Public/json/CSV2SQL.i18n.espanol.json @@ -0,0 +1,3 @@ +{ + "espanol" : {} +} \ No newline at end of file diff --git a/Public/json/CSV2SQL.i18n.galego.json b/Public/json/CSV2SQL.i18n.galego.json new file mode 100755 index 0000000..8761660 --- /dev/null +++ b/Public/json/CSV2SQL.i18n.galego.json @@ -0,0 +1,3 @@ +{ + "galego" : {} +} \ No newline at end of file diff --git a/Public/json/CSV2SQL.i18n.nihongo.json b/Public/json/CSV2SQL.i18n.nihongo.json new file mode 100755 index 0000000..118b7cb --- /dev/null +++ b/Public/json/CSV2SQL.i18n.nihongo.json @@ -0,0 +1,3 @@ +{ + "nihongo" : {} +} \ No newline at end of file diff --git a/Public/json/CSV2SQL.i18n.russkiy.json b/Public/json/CSV2SQL.i18n.russkiy.json new file mode 100755 index 0000000..1923ac4 --- /dev/null +++ b/Public/json/CSV2SQL.i18n.russkiy.json @@ -0,0 +1,3 @@ +{ + "russkiy" : {} +} \ No newline at end of file diff --git a/Public/json/CSV2SQL.routes.json b/Public/json/CSV2SQL.routes.json new file mode 100755 index 0000000..36165ee --- /dev/null +++ b/Public/json/CSV2SQL.routes.json @@ -0,0 +1,3 @@ +[ + "/ files_csv_view" +] \ No newline at end of file diff --git a/Public/json/CSV2SQL.settings.json b/Public/json/CSV2SQL.settings.json new file mode 100755 index 0000000..be89570 --- /dev/null +++ b/Public/json/CSV2SQL.settings.json @@ -0,0 +1,39 @@ +[ + + ["ANP", { + "application_name" : "CSV2SQL", + "application_url" : "https://csv2sql.k3y.pw/", + "application_git" : "https://git.k3y.pw/KyMAN/CSV2SQL", + "application_logo" : "/images/CSV2SQL.webp", + "default_avatar" : "https://anp.k3y.pw/images/AnP.png", + "i18n_files" : [ + "/json/CSV2SQL.i18n.english.json", + "/json/CSV2SQL.i18n.espanol.json", + "/json/CSV2SQL.i18n.galego.json", + "/json/CSV2SQL.i18n.nihongo.json", + "/json/CSV2SQL.i18n.russkiy.json" + ], + "default_language" : "espanol", + "views_files" : "/json/CSV2SQL.views.json", + "routes_files" : "/json/CSV2SQL.routes.json", + "class" : "csv2sql", + "main_menu_items" : [ + {"i18n" : "documentation", "icon" : "documentation", "url" : "https://csv2sql.k3y.pw/doc"}, + {"i18n" : "git", "icon" : "git", "url" : "https://git.k3y.pw/KyMAN/CSV2SQL"} + ], + "cells" : 80, + "minimum_font_size" : 14, + "allow_users" : false, + "allow_geolocation" : false, + "allow_breadcrumb" : false + }, "ANP"], + + ["CSV2SQL", { + "default_sql_server_reserved_words" : [], + "process_exception_print" : true, + "mysql_tabulation" : " ", + "sql_server_tabulation" : "\t", + "sql_server_insert_division" : 900 + }, "CSV2SQL"] + +] \ No newline at end of file diff --git a/Public/json/CSV2SQL.views.json b/Public/json/CSV2SQL.views.json new file mode 100755 index 0000000..590bc12 --- /dev/null +++ b/Public/json/CSV2SQL.views.json @@ -0,0 +1,31 @@ +{ + "files_csv_view" : { + "type" : "form", + "i18n" : "files_csv", + "structure" : [ + {"name" : "default_database", "type" : "text"}, + {"name" : "type", "type" : "selector", "options" : [ + {"name" : "SQL Server", "value" : "sqlserver"}, + {"name" : "MySQL/MariaDB", "value" : "mysql", "selected" : true} + ]}, + {"name" : "default_creator_database", "type" : "checkbox", "checked" : true}, + {"name" : "default_remover_tables", "type" : "checkbox", "checked" : true}, + {"name" : "default_creator_tables", "type" : "checkbox", "checked" : true}, + {"name" : "default_updater_tables", "type" : "checkbox", "checked" : true}, + {"name" : "default_filler_tables", "type" : "checkbox", "checked" : true}, + {"name" : "default_uniques", "type" : "text", "multiline" : true}, + {"name" : "default_id_attribute", "type" : "checkbox", "checked" : true}, + {"name" : "default_deleted_attribute", "type" : "checkbox", "checked" : false}, + {"name" : "default_date_in_attribute", "type" : "checkbox", "checked" : true}, + {"name" : "default_date_out_attribute", "type" : "checkbox", "checked" : true}, + {"name" : "default_fill_last_attribute", "type" : "checkbox", "checked" : true}, + {"name" : "files", "type" : "file", "multiple" : true, "onchange" : "{object_name}.create_subforms(this, event);", "accept" : ".csv"}, + {"name" : "files_data"}, + {"name" : "file_name", "type" : "text", "value" : "csv2sql"} + ], + "buttons" : [ + {"i18n" : "download_files", "icon" : "download_files", "onclick" : "{object_name}.download_files(this, event);"}, + {"i18n" : "download_one_file", "icon" : "download_one_file", "onclick" : "{object_name}.download_one_file(this, event);"} + ] + } +} \ No newline at end of file diff --git a/Public/scss/CSV2SQL.css b/Public/scss/CSV2SQL.css new file mode 100755 index 0000000..2eff65b --- /dev/null +++ b/Public/scss/CSV2SQL.css @@ -0,0 +1,4 @@ +.csv2sql .field[data-i18n=files_data] .buttons { + display: none; } + +/*# sourceMappingURL=CSV2SQL.css.map */ diff --git a/Public/scss/CSV2SQL.css.map b/Public/scss/CSV2SQL.css.map new file mode 100755 index 0000000..8d268f3 --- /dev/null +++ b/Public/scss/CSV2SQL.css.map @@ -0,0 +1,7 @@ +{ +"version": 3, +"mappings": "AAEI,8CAAqC;EAAC,OAAO,EAAG,IAAI", +"sources": ["CSV2SQL.scss"], +"names": [], +"file": "CSV2SQL.css" +} diff --git a/Public/scss/CSV2SQL.scss b/Public/scss/CSV2SQL.scss new file mode 100755 index 0000000..75b30b9 --- /dev/null +++ b/Public/scss/CSV2SQL.scss @@ -0,0 +1,5 @@ +.csv2sql{ + + .field[data-i18n=files_data] .buttons{display : none;} + +}