--
-- MySQL Workbench Doctrine Export Plugin
-- Version: 0.3.6
-- Authors: Johannes Mueller, Karsten Wutzke
-- Copyright (c) 2008-2009
--
-- http://code.google.com/p/mysql-workbench-doctrine-plugin/
--
-- * The export plugin allows you to export a catalog as Doctrine YAML schema.
-- * This plugin was tested with MySQL Workbench 5.1.10 OSS (beta2)
--
-- This file is free software: you can redistribute it and/or
-- modify it under the terms of the GNU Lesser General Public
-- License as published by the Free Software Foundation, either
-- version 3 of the License, or (at your option) any later version.
--
-- This library is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-- Lesser General Public License for more details.
--
-- You should have received a copy of the GNU Lesser General Public
-- License along with this library. If not, see .
--
---------------------------------------------------------------------------------------------
--
-- Special thanks to:
-- Daniel Haas who develops the MySQL Workbench Propel export plugin
-- and kindly agreed to adopt pieces of his source
-- http://www.diloc.de/blog/
--
---------------------------------------------------------------------------------------------
--
-- * IMPORTANT:
-- * If you find BUGS in this plugin or have ideas for IMPROVEMENTS or PATCHES, don't hesitate
-- * to contact us at http://code.google.com/p/mysql-workbench-doctrine-plugin/
--
-- INSTALLATION:
-- Just copy this file into the \modules folder of your
-- a. up until Workbench version 5.0.x installation directory or
-- b. starting with Workbench 5.1.x local user MySQL appdata directory
--
-- USAGE:
-- 1. Open MySQL Workbench
-- 2. Open the database schema
-- 3. Go to "Plugins" -> "Catalog"
-- 3a. Select "Doctrine Export: Copy [...] to Clipboard" to save the YAML output to your
-- OS's clipboard, just open a new file and paste it there
-- 3b. Select "Doctrine Export: Write [...] to File..." and save the YAML output to a text
-- file as specified in the dialog
--
-- NOTES:
-- 1. The YAML file extension usually is ".yml"
-- 2. The plugin locations from MySQL Workbench changed from version 5.0.x to 5.1.x.
-- 3. On Windows XP the Workbench:copyToClipboard function seems to have a defect in version
-- 5.1.9 up to 5.2.1alpha (other versions untested): http://bugs.mysql.com/bug.php?id=44461
-- 4. To change the schema character set and collation in Workbench 5.1.x you have to go to tab
-- "MySQL Model" -> "Physical Schemata", then double click that yellow DB image with the
-- schema name next to it.
--
-- CHANGELOG:
-- 0.3.6 (JM)
-- + [oth] changed convertion of INT from integer to integer(4)
-- see http://code.google.com/p/mysql-workbench-doctrine-plugin/issues/detail?id=10
-- 0.3.5 (JM)
-- + [fix] type mediumtext | mediumblob -> clob(16777215)
-- see http://code.google.com/p/mysql-workbench-doctrine-plugin/issues/detail?id=9
-- + [add] type longtext | longblob -> clob
-- type tinytext | tinyblob -> clob(255)
-- type text | blob -> clob(65535)
-- 0.3.4 (JM)
-- + [fix] multiple column unique indexes
-- see http://code.google.com/p/mysql-workbench-doctrine-plugin/issues/detail?id=8
-- + [add] preparation for cross database joins (works with MySQL and PostgreSQL and maybe others)
-- please switch the function getCrossDatabaseJoinsFlag() return value to "on" and restart
-- MySQL Workbench (may cause problems with symfony)
-- see http://www.doctrine-project.org/blog/cross-database-joins
-- 0.3.3 (JM)
-- + [add] support for I18n schemes with *_translation tables
-- see http://code.google.com/p/mysql-workbench-doctrine-plugin/issues/detail?id=7
-- + [oth] replaced code indent tabs with spaces
-- 0.3.2 (Karsten Wutzke)
-- + [oth] small change in handling version information
-- 0.3.1 (JM)
-- + [fix] changed simple type "INT" to doctrine "integer"
-- see http://code.google.com/p/mysql-workbench-doctrine-plugin/issues/detail?id=6
-- 0.3 (Karsten Wutzke)
-- + [fix] types BOOLEAN, BOOL, and INTEGER now working (are no simpleTypes)
-- + [add] lowercasing for default TRUE and FALSE keywords
-- + [imp] default NULL, TRUE, and FALSE detected case-insensitively now (WB does not
-- uppercase default values as opposed to all data types - which are keywords, too)
-- + [add] added version info to module ID and menu items, like this plugins with different
-- versions can be used at the same time (starting with this version and one old)
-- + [imp] file export: added simple functionality to append ".yml" extension to file paths
-- not ending with ".yml"
-- + [imp] removed some unnecessary prints
-- + [imp] shortened changelog entry types [improvement] to [imp] and [other] to [oth]
-- 0.2 (Karsten Wutzke)
-- + [add] foreignAlias for relations
-- + [fix] exception thrown in relationBuilding on some tables with foreign keys where the
-- column and referenced columns list has zero length
-- + [imp] replaced all string.len() calls with the length operator #s
-- + [add] function string.endswith()
-- + [imp] eased the code of function exportYamlSchemaToFile (eliminated double if)
-- + [add] functions to test if a (table) name is plural or singular
-- + [fix] reanimated functionality for (English) plural table names
-- + [add] functionality to adjust special (English) table names ending with "ies" to
-- convert "ie" to "y" ("Countries" -> "Country") and more
-- + [add] data type conversion of integer types and CHAR, BOOLEAN, and BOOL:
-- TINYINT -> integer(1)
-- SMALLINT -> integer(2)
-- MEDIUMINT -> integer(3)
-- INT -> integer
-- INTEGER -> integer
-- BIGINT -> integer(8)
-- BOOLEAN -> boolean
-- BOOL -> boolean
-- CHAR -> string + fixed option
-- + [add] option for CHAR columns
-- + [imp] removed using the table name capitalization function (ucfirst) from
-- function buildTableName(), like this tables retain their original names and the
-- default Workbench naming convention "_has_" still gets handled correctly
-- + [imp] replaced "\r\n" line endings with "\n" only
-- + [imp] using lowercase for default null values
-- + [imp] restructured MySQL plugin init code for easier understanding
-- 0.1alpha9
-- + [add] function to save to file
-- + [add] print version name on execution in debug window
-- 0.1alpha8
-- + [fix] changed behavior of table renaming (thanks to Francisco Ernesto Teixeira)
-- taBleNaMe -> Tablename ->[fix]-> TaBleNaMe
-- 0.1alpha7
-- + [oth] changed the license from GPLv2 to LGPLv3
-- + [fix] removed plural correction of table names (deprecated in Doctrine 1.0)
-- 0.1alpha6
-- + [fix] some conversion from workbench type to Doctrine type
-- BIGINT -> INTEGER
-- DATETIME -> TIMESTAMP
-- + [fix] decimal (precision + scale)
-- + [fix] enum handling
-- 0.1alpha5 by quocbao (qbao.nguyen@gmail.com)
-- + [fix] some conversion from workbench type to Doctrine type
-- + [fix] removed generate_accessors [deprecated]
-- 0.1alpha4
-- + [add] tables_has_names -> TablesName ->[fix]-> TableName
-- + [add] rename columns "idtable | table_idtable" -> "id | table_id"
-- 0.1alpha3
-- + [add] convert underscores in tablenames to CamelCase
-- 0.1alpha2
-- + [add] nested set support for tablenames ending with _ns
-- 0.1alpha1
-- supports:
-- + [add] indexes [fulltext, unique, index]
-- + [add] index length
-- + [add] collation
-- + [add] character set
-- + [add] engine [MySQL, InnoDB]
-- + [add] relations
-- + [add] foreign key constraints
-- + [add] table name fixing
-- + [add] column flags [binary, zerofill, unsigned]
-- + [add] autoincrement
-- + [add] not null
-- + [add] default values
-- + [add] decimal precision
-- + [add] column length [e.g. varchar(255)]
--
----------------------------------------------------------------------------------------------
function getCrossDatabaseJoinsFlag()
-- Switch this flag to "on" if you want to use
-- cross database joins described on
-- http://www.doctrine-project.org/blog/cross-database-joins
-- this may break symfony models
-- return "on|off"
return "off"
end
-- standard plugin functions
--
-- this function is called first by MySQL Workbench core to determine number of
-- plugins in this module and basic plugin info
-- see the comments in the function body and adjust the parameters as appropriate
--
function getModuleInfo()
-- module properties
local props =
{
-- module name (ID)
name = "DoctrineExport",
-- module author(s)
author = "various",
--module version
version = "0.3.6",
-- interface implemented by this module
implements = "PluginInterface",
-- plugin functions exposed by this module
-- l looks like a parameterized list, i instance, o object, @ fully qualified class name
functions =
{
"getPluginInfo:l:",
"exportYamlSchemaToClipboard:i:o@db.Catalog",
"exportYamlSchemaToFile:i:o@db.Catalog"
}
}
-- can't assign inside declaration
props.name = props.name .. props.version
return props
end
function objectPluginInput(type)
return grtV.newObj("app.PluginObjectInput", {objectStructName = type})
end
function getPluginInfo()
-- list of plugins this module exposes (list object of type app.Plugin?)
local l = grtV.newList("object", "app.Plugin")
-- plugin instances
local plugin
local props = getModuleInfo()
-- new plugin: export to clipboard
plugin = createNewPlugin("wb.catalog.util.exportYamlSchemaToClipboard" .. props.version,
"Doctrine Export " .. props.version .. ": Copy Generated Doctrine Schema to Clipboard",
props.name,
"exportYamlSchemaToClipboard",
{objectPluginInput("db.Catalog")},
{"Catalog/Utilities", "Menu/Catalog"})
-- append to list of plugins
grtV.insert(l, plugin)
-- new plugin: export to file
plugin = createNewPlugin("wb.catalog.util.exportYamlSchemaToFile" .. props.version,
"Doctrine Export " .. props.version .. ": Write Generated Doctrine Schema to File...",
props.name,
"exportYamlSchemaToFile",
{objectPluginInput("db.Catalog")},
{"Catalog/Utilities", "Menu/Catalog"})
-- append to list of plugins
grtV.insert(l, plugin)
return l
end
function createNewPlugin(name, caption, moduleName, moduleFunctionName, inputValues, groups)
-- create dictionary, Lua seems to handle keys and values right...
local props =
{
name = name,
caption = caption,
moduleName = moduleName,
pluginType = "normal",
moduleFunctionName = moduleFunctionName,
inputValues = inputValues,
rating = 100,
showProgress = 0,
groups = groups
}
local plugin = grtV.newObj("app.Plugin", props)
-- set owner???
plugin.inputValues[1].owner = plugin
return plugin
end
-- ############################
-- ## change from here ##
-- ############################
--
-- Print some version information and copyright to the output window
function printVersion()
print("\n\n\nDoctrine Export v" .. getModuleInfo().version .. "\nCopyright (c) 2008 - 2009 Johannes Mueller, Karsten Wutzke - License: LGPLv3");
end
--
-- Convert workbench simple types to doctrine types
function wbSimpleType2DoctrineDatatype(column)
--print("\n")
--print(column)
local doctrineType
-- boolean, bool, and integer don't seem to be simple types, but rather user types...
if ( column.simpleType ~= nil ) then
doctrineType = column.simpleType.name
--print("\n" .. column.name .. " type = " .. column.simpleType.name)
-- convert VARCHAR and CHAR to string
if ( column.simpleType.name == "VARCHAR" or column.simpleType.name == "CHAR" ) then
doctrineType = "string"
end
-- convert TINYINT to integer(1)
if ( column.simpleType.name == "TINYINT" ) then
doctrineType = "integer(1)"
end
-- convert SMALLINT to integer(2)
if ( column.simpleType.name == "SMALLINT" ) then
doctrineType = "integer(2)"
end
-- convert MEDIUMINT to integer(3)
if ( column.simpleType.name == "MEDIUMINT" ) then
doctrineType = "integer(3)"
end
-- convert INT to integer (Doctrine does not know "int")
if ( column.simpleType.name == "INT" ) then
doctrineType = "integer(4)"
end
-- convert BIGINT to integer(8)
if ( column.simpleType.name == "BIGINT" ) then
doctrineType = "integer(8)"
end
-- decimal
if ( column.simpleType.name == "DECIMAL" ) then
doctrineType = "decimal"
if ( column.precision ~= nil ) then
doctrineType = doctrineType .. "(" .. column.precision .. "," .. column.scale .. ")"
end
end
-- tinytext or tinyblob
if ( column.simpleType.name == "TINYTEXT" or column.simpleType.name == "TINYBLOB" ) then
doctrineType = "clob(255)"
end
-- text or blob
if ( column.simpleType.name == "TEXT" or column.simpleType.name == "BLOB" ) then
doctrineType = "clob(65535)"
end
-- mediumtext or mediumblob
if ( column.simpleType.name == "MEDIUMTEXT" or column.simpleType.name == "MEDIUMBLOB" ) then
doctrineType = "clob(16777215)"
end
-- longtext or longblob
if ( column.simpleType.name == "LONGTEXT" or column.simpleType.name == "LONGBLOB" ) then
doctrineType = "clob"
end
-- convert DATETIME to TIMESTAMP (DATETIME is not ISO/IEC standard SQL)
if ( column.simpleType.name == "DATETIME" ) then
doctrineType = "timestamp"
end
return string.lower(doctrineType)
elseif ( column.userType ~= nil ) then
--print("\n" .. column.name .. " type = " .. column.userType.name)
if ( column.userType.name == "INTEGER" ) then
doctrineType = "integer"
end
-- convert BOOLEAN and BOOL to boolean
if ( column.userType.name == "BOOLEAN" or column.userType.name == "BOOL" ) then
doctrineType = "boolean"
end
return string.lower(doctrineType)
elseif ( column.structuredType ~= nil ) then
--print("\n" .. column.name .. " type = " .. column.structuredType.name)
return "structuredType (not implemented yet)"
else
return "unknown"
end
end
--
-- handle enums for doctrine
function handleEnum(column)
if ( column.datatypeExplicitParams ~= nil ) then
local s = column.datatypeExplicitParams
s = string.sub(s, 2, #s - 1)
return s
end
return ""
end
--
-- converts first character of given string to uppercase
function ucfirst(s)
-- only capitalize the very first char, leave all others untouched
return string.upper(string.sub(s, 0, 1)) .. string.sub(s, 2, #s)
-- old: lowers rest for whatever reason
--return string.upper(string.sub(s, 0, 1)) .. string.lower(string.sub(s, 2, #s))
end
--
-- converts a table_name to tableName
function underscoresToCamelCase(s)
s = string.gsub(s, "_(%w)", function(v)
return string.upper(v)
end)
return s
end
--
-- rename idtable to id
-- rename table_idtable to table_id
function renameIdColumns(s)
s = string.gsub(s, "(id%w+)", function(v)
return "id"
end)
return s
end
--
-- changing tableNames of workbench into
-- doctrine friendly tableNames
function buildTableName(s)
-- don't call ucfirst, leave table names as they are
--s = ucfirst(s)
if ( isNestedTableModel(s) ) then
s = string.sub(s, 1, #s - 3)
end
--
-- converting User_has_Groups (default WB-Scheme) to UserGroups
-- as used in the doctrine manual
local patternStart, patternEnd = string.find(s, "_has_")
if ( patternStart ~= nil and patternEnd ~= nil ) then
local front = singularizeTableName(string.sub(s, 1, patternStart - 1))
local back = string.sub(s, patternEnd + 1)
s = ucfirst(front) .. ucfirst(back)
end
s = singularizeTableName(s)
--
-- make camel_case to CamelCase
s = underscoresToCamelCase(s)
return s
end
-- extend string functionality
function string.endswith(s, suffix)
return s:sub(#s - #suffix + 1) == suffix
end
function isPlural(s)
-- is plural if string ends with an "s" but not with "ss"
return string.endswith(s, "s") and not string.endswith(s, "ss") and #s > 1
end
function isSingular(s)
-- is singular if not plural
return not isPlural(s)
end
--
-- remove plural of tableNames
-- Groups becomes Group
function singularizeTableName(s)
-- is plural?
if ( isPlural(s) ) then
-- strip "s"
s = string.sub(s, 1, #s - 1)
-- we can't just strip the s without looking at the remaining English plural endings
-- see http://en.wikipedia.org/wiki/English_plural
-- if the table name ends with "e" ("coache", "hashe", "addresse", "buzze", "heroe", ...)
if ( string.endswith(s, "che")
or string.endswith(s, "she")
or string.endswith(s, "sse")
or string.endswith(s, "zze")
or string.endswith(s, "oe") ) then
-- strip an "e", too
s = string.sub(s, 1, #s - 1)
-- if table name ends with "ie"
elseif ( string.endswith(s, "ie") ) then
-- replace "ie" by a "y" ("countrie" -> "country", "hobbie" -> "hobby", ...)
s = string.sub(s, 1, #s - 2) .. "y"
elseif ( string.endswith(s, "ve") ) then
-- replace "ve" by an "f" ("calve" -> "calf", "leave" -> "leaf", ...)
s = string.sub(s, 1, #s - 2) .. "f"
-- does *not* work for certain words ("knive" -> "knif", "stave" -> "staf", ...): TODO (hard)
else
-- do nothing ("game", "referee", "monkey", ...)
-- note: table names like "Caches" can't be handled correctly because of the "che" rule above,
-- that word however basically stems from French and might be considered a special case anyway
-- also collective names like "Personnel", "Cast" (caution: SQL keyword!) can't be singularized
end
end
return s
end
function pluralizeTableName(s)
-- is singular?
if ( isSingular(s) ) then
-- we can't just append the s without looking at the English singular endings
-- see http://en.wikipedia.org/wiki/English_plural
-- if the table name ends with "ch", "sh", "ss" or "zz" ("coach", "hash", "address", "buzz", "hero", ...)
if ( string.endswith(s, "ch")
or string.endswith(s, "sh")
or string.endswith(s, "ss")
or string.endswith(s, "zz")
or string.endswith(s, "o") ) then
-- append "es"
s = s .. "es"
-- if table name ends with "y"
elseif ( string.endswith(s, "y") ) then
-- replace "y" with "ies" ("country" -> "countries", "hobby" -> "hobbies", ...)
s = string.sub(s, 1, #s - 1) .. "ies"
elseif ( string.endswith(s, "f") ) then
-- replace "f" by an "ves" ("leaf" -> "leaves", "half" -> "halves", ...)
s = string.sub(s, 1, #s - 1) .. "ves"
else
-- append "s" ("games", "referees", "monkeys", ...)
s = s .. "s"
end
end
return s
end
--
-- checks if a given string ends with _ns
-- which means it is a NestedSet Table
function isNestedTableModel(s)
if ( string.sub(s, #s - 2 ) == '_ns' ) then
return true
end
return false
end
--
-- building yaml for relations of a given
-- foreignKey
function relationBuilding(tbl, tables)
local i, k
local foreignKey = nil
local relations = " relations:\n"
for k = 1, grtV.getn(tbl.foreignKeys) do
foreignKey = tbl.foreignKeys[k]
relations = relations .. " " .. buildTableName(foreignKey.referencedTable.name) .. ":\n"
-- check zero length
if ( #foreignKey.columns > 0 ) then
relations = relations .. " local: " .. renameIdColumns(foreignKey.columns[1].name) .. "\n"
end
-- check zero length
if ( #foreignKey.referencedColumns > 0 ) then
relations = relations .. " foreign: " .. renameIdColumns(foreignKey.referencedColumns[1].name) .. "\n"
relations = relations .. " foreignAlias: " .. pluralizeTableName(buildTableName(tbl.name)) .. "\n"
end
if ( foreignKey.deleteRule ~= nil and foreignKey.deleteRule ~= "" and foreignKey.deleteRule ~= "NO ACTION" ) then
relations = relations .. " onDelete: " .. string.lower( foreignKey.deleteRule ) .. "\n"
end
if ( foreignKey.updateRule ~= nil and foreignKey.updateRule ~= "" and foreignKey.updateRule ~= "NO ACTION" ) then
relations = relations .. " onUpdate: " .. string.lower( foreignKey.updateRule ) .. "\n"
end
--if ( foreignKey.many == 1 ) then
-- relations = relations .. " type: many\n"
--end
end
if ( foreignKey ~= nil ) then
return relations
end
return ""
end
--
-- check for *_translation table
-- related to I18n Support in doctrine
function hasTranslationTableModel(tblname, tables)
local k
tblname = tblname .. "_translation"
for k = 1, grtV.getn(tables) do
if ( tblname == tables[k].name ) then
return true
end
end
return false
end
--
-- returns a reference of the translation table
-- by given table name
function getTranslationTableModel(tblname, tables)
local k
tblname = tblname .. "_translation"
for k = 1, grtV.getn(tables) do
if ( tblname == tables[k].name ) then
return tables[k]
end
end
end
--
-- build a list of the I18n fields by a given
-- table name works only if *_translation table of
-- given tblname exist
function buildActAsI18nFieldsList(tblname, tables)
local k, l
local returnText = " fields: ["
tblname = tblname .. "_translation"
for k = 1, grtV.getn(tables) do
if ( tblname == tables[k].name ) then
for l = 1, grtV.getn(tables[k].columns) do
col = tables[k].columns[l]
if ( col.name ~= "id" and col.name ~= "lang" ) then
returnText = returnText .. col.name .. ", "
end
end
end
end
returnText = string.sub(returnText, 1, #returnText - 2)
returnText = returnText .. "]\n"
return returnText
end
--
-- generates the yaml schema
function generateYamlSchema(cat)
local i, j, schema, tbl
local yaml = "---\n"
local optionsSetFlag = false
for i = 1, grtV.getn(cat.schemata) do
schema = cat.schemata[i]
--print(schema)
if ( optionsSetFlag == false ) then
-- automatically detect relations
yaml = yaml .. "detect_relations: true\n"
--
-- set basic options
yaml = yaml .. "options:\n"
if ( schema.defaultCollationName ~= nil and schema.defaultCollationName ~= "" ) then
yaml = yaml .. " collation: " .. schema.defaultCollationName .. "\n"
end
if ( schema.defaultCharacterSetName ~= nil and schema.defaultCharacterSetName ~= "" ) then
yaml = yaml .. " charset: " .. schema.defaultCharacterSetName .. "\n"
end
-- does not exist
-- yaml = yaml .. " type: " .. schema.defaultStorageEngineName .. "\n"
yaml = yaml .. " type: " .. "InnoDB" .. "\n"
yaml = yaml .. "\n"
optionsSetFlag = true
end
--print(schema)
for j = 1, grtV.getn(schema.tables) do
tbl = schema.tables[j]
--
-- do not export *_translation tables
if ( string.endswith(tbl.name, "_translation") == false ) then
yaml = buildYamlForSingleTable(tbl, schema, yaml)
end
end
end
--print(yaml)
return yaml
end
function buildYamlForSingleColumn(tbl, col, yaml)
local l, m
doctrineType = wbSimpleType2DoctrineDatatype(col)
--
-- start of adding a column
yaml = yaml.." "..renameIdColumns(col.name)..":\n"
yaml = yaml.." type: " .. doctrineType
if ( doctrineType == "enum" ) then
-- enum handling
yaml = yaml.."\n"
yaml = yaml.." values: ["
yaml = yaml.. handleEnum(col)
yaml = yaml.."]"
end
if ( col.length ~= -1 ) then
yaml = yaml.. "(" ..col.length.. ")"
end
yaml = yaml.."\n"
for m = 1, grtV.getn(tbl.indices) do
index = tbl.indices[m]
--
-- checking for primary index
if ( index.indexType == "PRIMARY" ) then
for l = 1, grtV.getn(index.columns) do
column = index.columns[l]
if ( column.referencedColumn.name == col.name ) then
yaml = yaml .." primary: true\n"
end
end
end
--
-- checking for unique index
if ( index.indexType == "UNIQUE" ) then
-- check if just one column in index
if ( grtV.getn(index.columns) == 1 ) then
for l = 1, grtV.getn(index.columns) do
column = index.columns[l]
if ( column.referencedColumn.name == col.name ) then
yaml = yaml .. " unique: true\n"
end
end
end
end
end
--
-- setting flags
if ( col.flags ~= nil ) then
local flag
for l = 1, grtV.getn(col.flags) do
flag = grtV.toLua(col.flags[l])
if ( flag ~= nil ) then
if ( flag == "UNSIGNED" ) then
yaml = yaml .. " unsigned: true\n"
end
if ( flag == "BINARY" ) then
yaml = yaml .. " binary: true\n"
end
if ( flag == "ZEROFILL" ) then
yaml = yaml .. " zerofill: true\n"
end
end
end
end
--
-- checking for mysql column option not null
if ( col.isNotNull == 1 ) then
yaml = yaml.." notnull: true\n"
end
--
-- checking for default value of a column
if ( col.defaultValue ~= '' and string.upper(col.defaultValue) ~= 'CURRENT_TIMESTAMP' ) then
yaml = yaml .. " default: "
-- Lua has no switch...
-- switch ( string.upper(col.defaultValue) )
-- if null, true, or false then lowercase
if ( string.upper(col.defaultValue) == "NULL"
or string.upper(col.defaultValue) == "TRUE"
or string.upper(col.defaultValue) == "FALSE" ) then
yaml = yaml .. string.lower(col.defaultValue)
else
yaml = yaml .. col.defaultValue
end
yaml = yaml .. "\n"
end
--
-- checking for autoincrement of a column
if ( col.autoIncrement == 1 ) then
yaml = yaml.." autoincrement: true\n"
end
-- if CHAR type, set fixed flag
if ( col.simpleType ~= nil and col.simpleType.name == "CHAR" ) then
yaml = yaml.." fixed: true\n"
end
return yaml
end
function buildYamlForSingleTable(tbl, schema, yaml)
local k, l, col, index, column
local actAsPart = ""
--
-- start of adding a table
yaml = yaml .. buildTableName(tbl.name) .. ":\n"
-- test singularize and pluralize functions
--print("\n" .. singularizeTableName(tbl.name))
--print(" <-> ")
--print(pluralizeTableName(tbl.name))
--
-- add the real table name to the model
if ( buildTableName(tbl.name) ~= tbl.name and getCrossDatabaseJoinsFlag() ~= "on" ) then
yaml = yaml .. " tableName: " .. tbl.name .. "\n"
end
if ( getCrossDatabaseJoinsFlag() == "on" ) then
yaml = yaml .. " tableName: " .. schema.name .. "." .. tbl.name .. "\n"
yaml = yaml .. " connection: " .. schema.name .. "\n"
end
-- check if table ends with _ns means
-- NestedSet Model
if ( isNestedTableModel(tbl.name) ) then
actAsPart = actAsPart .. " NestedSet:\n"
end
--
-- check for I18n tables
if ( hasTranslationTableModel(tbl.name, schema.tables) ) then
actAsPart = actAsPart .. " I18n:\n"
actAsPart = actAsPart .. buildActAsI18nFieldsList(tbl.name, schema.tables)
end
--
-- add ActAs: part to the table model
if ( string.len(actAsPart) > 0 ) then
yaml = yaml .. " actAs:\n"
yaml = yaml .. actAsPart
end
--
-- iterate through the table columns
yaml = yaml .. " columns:\n"
for k = 1, grtV.getn(tbl.columns) do
col = tbl.columns[k]
yaml = buildYamlForSingleColumn(tbl, col, yaml)
end
--
-- hack for adding columns outsourced
-- to a *_translation table
if ( hasTranslationTableModel(tbl.name, schema.tables) ) then
local translationTable
translationTable = getTranslationTableModel(tbl.name, schema.tables)
for k = 1, grtV.getn(translationTable.columns) do
col = translationTable.columns[k]
if ( col.name ~= "id" and col.name ~= "lang" ) then
yaml = buildYamlForSingleColumn(tbl, col, yaml)
end
end
end
--
-- add foreign keys
yaml = yaml .. relationBuilding(tbl, schema.tables)
--
-- add missing indices
local indexes = ""
for k = 1, grtV.getn(tbl.indices) do
index = tbl.indices[k]
if ( index.indexType == "INDEX" ) then
indexes = indexes .. " " .. index.name .. ":\n"
indexes = indexes .. " fields: ["
for l = 1, grtV.getn(index.columns) do
column = index.columns[l]
indexes = indexes .. renameIdColumns(column.referencedColumn.name)
if ( l < grtV.getn(index.columns) ) then
indexes = indexes .. ", "
end
end
indexes = indexes .. "]\n"
if ( index.keyBlockSize ~= nil and index.keyBlockSize ~= 0 ) then
indexes = indexes .. " length: " .. index.keyBlockSize .. "\n"
end
end
if ( index.indexType == "FULLTEXT" ) then
indexes = indexes .. " " .. index.name .. ":\n"
indexes = indexes .. " fields: ["
for l = 1, grtV.getn(index.columns) do
column = index.columns[l]
indexes = indexes .. renameIdColumns(column.referencedColumn.name)
if ( l < grtV.getn(index.columns) ) then
indexes = indexes .. ", "
end
end
indexes = indexes .. "]\n"
indexes = indexes .. " type: fulltext\n"
end
if ( index.indexType == "UNIQUE" ) then
-- check if more than 1 column in index
-- otherwise ignore
if( grtV.getn(index.columns) > 1 ) then
indexes = indexes .. " " .. index.name .. ":\n"
indexes = indexes .. " fields:\n"
for l = 1, grtV.getn(index.columns) do
column = index.columns[l]
indexes = indexes .. " " .. renameIdColumns(column.referencedColumn.name) .. ":\n"
-- check if column in index is ASC or DESC
if ( column.descend ~= nil and column.descend ~= "" ) then
if ( column.descend == 0 ) then
indexes = indexes .. " sorting: ASC\n"
else
indexes = indexes .. " sorting: DESC\n"
end
end
-- check for column length in index
if ( column.columnLength ~= nil and column.columnLength ~= "" and column.columnLength ~= 0 ) then
indexes = indexes .. " length: " .. column.columnLength .. "\n"
end
end
indexes = indexes .. " type: unique\n"
end
end
end
if ( indexes ~= "" ) then
yaml = yaml .. " indexes:\n" .. indexes
end
--
-- add the options
local options = ""
if ( tbl.defaultCharacterSetName ~= nil and tbl.defaultCharacterSetName ~= "" ) then
options = options .. " charset: " .. tbl.defaultCharacterSetName .. "\n"
end
if ( tbl.defaultCollationName ~= nil and tbl.defaultCollationName ~= "" ) then
options = options .. " collate: " .. tbl.defaultCollationName .. "\n"
end
if ( tbl.tableEngine ~= nil and tbl.tableEngine ~= "" ) then
options = options .. " type: " .. tbl.tableEngine .. "\n"
end
if ( options ~= "" ) then
yaml = yaml .. " options:\n" .. options
end
-- final line break
return yaml .. "\n"
end
---------------------------------------------------------------------------------------------------
-- export function #1
function exportYamlSchemaToClipboard(catalog)
printVersion()
local yaml = generateYamlSchema(catalog)
Workbench:copyToClipboard(yaml)
print('\n > YAML schema copied to clipboard')
return 0
end
-- export function #2
function exportYamlSchemaToFile(catalog)
printVersion()
local yaml = generateYamlSchema(catalog)
local file = catalog.customData["doctrineExportPath"]
--print("\nFilepath is: " .. file)
if ( file ~= nil and
Workbench:confirm("Overwrite?", "Do you want to overwrite the previously exported file " .. file .. "?") == 1 ) then
-- global
doctrineExportPath = file
else
doctrineExportPath = Workbench:input("Please enter a path to the file to export the doctrine schema to.")
if ( doctrineExportPath ~= "" ) then
-- Try to save the filepath for the next time:
-- if file path doesn't end with .yml, append that
if ( not string.endswith(doctrineExportPath, ".yml") ) then
if ( string.endswith(doctrineExportPath, ".") ) then
doctrineExportPath = doctrineExportPath .. "yml"
else
doctrineExportPath = doctrineExportPath .. ".yml"
end
end
catalog.customData["doctrineExportPath"] = doctrineExportPath
end
end
if ( doctrineExportPath ~= '' ) then
f = io.open(doctrineExportPath, "w")
if ( f ~= nil ) then
f.write(f, yaml)
f.close(f)
print('\n > Doctrine schema was written to file ' .. doctrineExportPath)
else
print('\n > Could not open file for writing ' .. doctrineExportPath .. '!')
end
else
print('\n > Doctrine schema not exported as no path was given!')
end
return 0
end