From 43f242b8adee90d13f9cde1946ef940b24d9470b Mon Sep 17 00:00:00 2001 From: jordanclark Date: Thu, 28 Mar 2013 12:49:04 -0700 Subject: [PATCH 01/17] Better $getColumnDefinition I modified $getColumnDefinition so it uses the wheels $dbinfo tag and also passes in the "pattern" argument so that it only returns a single column, instead of the whole table. --- basefunctions.cfm | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/basefunctions.cfm b/basefunctions.cfm index 91d88e3..56948ba 100755 --- a/basefunctions.cfm +++ b/basefunctions.cfm @@ -75,10 +75,9 @@ - - - + loc = {}; + loc.columns = $dbinfo(type="columns",pattern=argumengs.columnName,table=arguments.tableName,datasource=application.wheels.dataSourceName,username=application.wheels.dataSourceUserName,password=application.wheels.dataSourcePassword); loc.columnDefinition = ""; loc.iEnd = loc.columns.RecordCount; for (loc.i=1; loc.i <= loc.iEnd; loc.i++) { @@ -107,4 +106,4 @@ } - + From 7da9247cb75e27ddb67392f305ab535a6a0fcd9e Mon Sep 17 00:00:00 2001 From: jordanclark Date: Thu, 28 Mar 2013 12:50:24 -0700 Subject: [PATCH 02/17] Abstracted addRecord into the adapters I moved most of the SQL building code from migration.cfc to /adapters/abstract.cfc This allows the adapter to add any special handling, which at this point is primarily to support SQL Server Identity Insert correctly --- Migration.cfc | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/Migration.cfc b/Migration.cfc index 6f32b35..73300e6 100644 --- a/Migration.cfc +++ b/Migration.cfc @@ -201,30 +201,14 @@ var loc = {}; - loc.columnNames = ""; - loc.columnValues = ""; + loc.values = {}; for (loc.key in arguments) { if(loc.key neq "table") { - loc.columnNames = ListAppend(loc.columnNames,this.adapter.quoteColumnName(loc.key)); - if(IsNumeric(arguments[loc.key])) { - loc.columnValues = ListAppend(loc.columnValues,arguments[loc.key]); - } else if(IsBoolean(arguments[loc.key])) { - loc.columnValues = ListAppend(loc.columnValues,IIf(arguments[loc.key],1,0)); - } else if(IsDate(arguments[loc.key])) { - loc.columnValues = ListAppend(loc.columnValues,"#arguments[loc.key]#"); - } else { - loc.columnValues = ListAppend(loc.columnValues,"'#ReplaceNoCase(arguments[loc.key],"'","''","all")#'"); - } + loc.values[ loc.key ] = arguments[ loc.key ]; } } - if(loc.columnNames != '') { - if(ListContainsNoCase(loc.columnnames, "[id]")) { - $execute(this.adapter.addRecordPrefix(arguments.table)); - } - $execute("INSERT INTO #this.adapter.quoteTableName(LCase(arguments.table))# ( #loc.columnNames# ) VALUES ( #loc.columnValues# )"); - if(ListContainsNoCase(loc.columnnames, "[id]")) { - $execute(this.adapter.addRecordSuffix(arguments.table)); - } + if( NOT structIsEmpty( loc.values ) ) { + $execute( this.adapter.addRecord( arguments.table, loc.values ) ); announce("Added record to table #arguments.table#"); } @@ -281,4 +265,4 @@ - \ No newline at end of file + From a5acb65ac10b5b652a78f3d296da97b606ae4a47 Mon Sep 17 00:00:00 2001 From: jordanclark Date: Thu, 28 Mar 2013 12:51:09 -0700 Subject: [PATCH 03/17] addRecord MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moved addRecord from migration.cfc to here, then adapters can override or extend the SQL INSERT  --- adapters/Abstract.cfc | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/adapters/Abstract.cfc b/adapters/Abstract.cfc index 5b95ae1..2a2c24d 100755 --- a/adapters/Abstract.cfc +++ b/adapters/Abstract.cfc @@ -280,13 +280,32 @@ - - - - - - - + + + + + + var loc = {}; + loc.sql = ""; + loc.columnNames = ""; + loc.columnValues = ""; + for (loc.key in arguments) { + loc.columnNames = ListAppend(loc.columnNames,this.adapter.quoteColumnName(loc.key)); + if(IsNumeric(arguments[loc.key])) { + loc.columnValues = ListAppend(loc.columnValues,arguments[loc.key]); + } else if(IsBoolean(arguments[loc.key])) { + loc.columnValues = ListAppend(loc.columnValues,IIf(arguments[loc.key],1,0)); + } else if(IsDate(arguments[loc.key])) { + loc.columnValues = ListAppend(loc.columnValues,arguments[loc.key]); + } else { + loc.columnValues = ListAppend(loc.columnValues,"'#ReplaceNoCase(arguments[loc.key],"'","''","all")#'"); + } + } + } + loc.sql = "INSERT INTO #quoteTableName(LCase(arguments.table))# ( #loc.columnNames# ) VALUES ( #loc.columnValues# )"; + + + - \ No newline at end of file + From e8f03867308bba7cca691c671d55fba4f0cf4776 Mon Sep 17 00:00:00 2001 From: jordanclark Date: Thu, 28 Mar 2013 12:54:08 -0700 Subject: [PATCH 04/17] addRecord with better identity_insert MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added $getIdentityColumn which gives the name of the "identity" column on the table. This is necessary because an identity column doesn't have to be the primary key. Extending abstract's addRecord method, this now checks for trying to insert a value into any "identity" column, not just one named "id". Removed addRecordPrefix & addRecordSuffix --- adapters/MicrosoftSQLServer.cfc | 42 +++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/adapters/MicrosoftSQLServer.cfc b/adapters/MicrosoftSQLServer.cfc index 3bc8d16..81529af 100755 --- a/adapters/MicrosoftSQLServer.cfc +++ b/adapters/MicrosoftSQLServer.cfc @@ -242,15 +242,43 @@ - - - - + + + + + loc = {}; + loc.columns = $dbinfo(type="columns",table=arguments.tableName,datasource=application.wheels.dataSourceName,username=application.wheels.dataSourceUserName,password=application.wheels.dataSourcePassword); + loc.identityCol = ""; + loc.iEnd = loc.columns.RecordCount; + for (loc.i=1; loc.i <= loc.iEnd; loc.i++) { + if( listFindNoCase( "identity", loc.columns["TYPE_NAME"][loc.i], " " ) + { + loc.identityCol = listAppend( loc.identityCol, loc.columns["COLUMN_NAME"][loc.i] ); + break; + } + } + + - + + - + + + var loc = {}; + loc.sql = super.addRecord( arguments.table, arguments.value ); + loc.identityCol= $getIdentityColumn( arguments.table ); + + // if trying to insert into an identity column wrap it with IDENTITY_INSERT ON/OFF + if( len( loc.identityCol ) AND listFindNoCase( structKeyList( arguments.values ), loc.identityCol ) ) { + loc.sql = "SET IDENTITY_INSERT #quoteTableName(LCase(arguments.table))# ON;" + & loc.sql & ";" + & "SET IDENTITY_INSERT #quoteTableName(LCase(arguments.table))# OFF;" + } + + - \ No newline at end of file + + From fcdf3ad3fc98a50e2aa7b30d97bd54091e81ed70 Mon Sep 17 00:00:00 2001 From: Jordan Clark Date: Thu, 28 Mar 2013 13:30:01 -0700 Subject: [PATCH 05/17] fix my previous changes to actually work --- adapters/Abstract.cfc | 23 +++++++++++------------ adapters/MicrosoftSQLServer.cfc | 13 ++++++------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/adapters/Abstract.cfc b/adapters/Abstract.cfc index 2a2c24d..5a259b6 100755 --- a/adapters/Abstract.cfc +++ b/adapters/Abstract.cfc @@ -289,17 +289,16 @@ loc.sql = ""; loc.columnNames = ""; loc.columnValues = ""; - for (loc.key in arguments) { - loc.columnNames = ListAppend(loc.columnNames,this.adapter.quoteColumnName(loc.key)); - if(IsNumeric(arguments[loc.key])) { - loc.columnValues = ListAppend(loc.columnValues,arguments[loc.key]); - } else if(IsBoolean(arguments[loc.key])) { - loc.columnValues = ListAppend(loc.columnValues,IIf(arguments[loc.key],1,0)); - } else if(IsDate(arguments[loc.key])) { - loc.columnValues = ListAppend(loc.columnValues,arguments[loc.key]); - } else { - loc.columnValues = ListAppend(loc.columnValues,"'#ReplaceNoCase(arguments[loc.key],"'","''","all")#'"); - } + for (loc.key in arguments.values) { + loc.columnNames = ListAppend(loc.columnNames,quoteColumnName(loc.key)); + if(IsNumeric(arguments.values[loc.key])) { + loc.columnValues = ListAppend(loc.columnValues,arguments.values[loc.key]); + } else if(IsBoolean(arguments.values[loc.key])) { + loc.columnValues = ListAppend(loc.columnValues,IIf(arguments.values[loc.key],1,0)); + } else if(IsDate(arguments.values[loc.key])) { + loc.columnValues = ListAppend(loc.columnValues,arguments.values[loc.key]); + } else { + loc.columnValues = ListAppend(loc.columnValues,"'#ReplaceNoCase(arguments.values[loc.key],"'","''","all")#'"); } } loc.sql = "INSERT INTO #quoteTableName(LCase(arguments.table))# ( #loc.columnNames# ) VALUES ( #loc.columnValues# )"; @@ -308,4 +307,4 @@ - + \ No newline at end of file diff --git a/adapters/MicrosoftSQLServer.cfc b/adapters/MicrosoftSQLServer.cfc index 81529af..69f9c83 100755 --- a/adapters/MicrosoftSQLServer.cfc +++ b/adapters/MicrosoftSQLServer.cfc @@ -251,8 +251,7 @@ loc.identityCol = ""; loc.iEnd = loc.columns.RecordCount; for (loc.i=1; loc.i <= loc.iEnd; loc.i++) { - if( listFindNoCase( "identity", loc.columns["TYPE_NAME"][loc.i], " " ) - { + if( listFindNoCase( loc.columns["TYPE_NAME"][loc.i], "identity", " " ) ) { loc.identityCol = listAppend( loc.identityCol, loc.columns["COLUMN_NAME"][loc.i] ); break; } @@ -267,18 +266,18 @@ var loc = {}; - loc.sql = super.addRecord( arguments.table, arguments.value ); + loc.sql = super.addRecord( arguments.table, arguments.values ); loc.identityCol= $getIdentityColumn( arguments.table ); // if trying to insert into an identity column wrap it with IDENTITY_INSERT ON/OFF if( len( loc.identityCol ) AND listFindNoCase( structKeyList( arguments.values ), loc.identityCol ) ) { - loc.sql = "SET IDENTITY_INSERT #quoteTableName(LCase(arguments.table))# ON;" - & loc.sql & ";" - & "SET IDENTITY_INSERT #quoteTableName(LCase(arguments.table))# OFF;" + loc.sql = "SET IDENTITY_INSERT #quoteTableName(LCase(arguments.table))# ON;" & chr(10) + & loc.sql & ";" & chr(10) + & "SET IDENTITY_INSERT #quoteTableName(LCase(arguments.table))# OFF;" & chr(10) } - + \ No newline at end of file From eaa4d8dc555e175ab7d69409da29d2a22da4cc7e Mon Sep 17 00:00:00 2001 From: Jordan Clark Date: Thu, 28 Mar 2013 14:53:02 -0700 Subject: [PATCH 06/17] added new "money" type for all databases added new limit options for integers, dates, & money (maps to decimal on non-mssql db) handy new methods mediumInteger(), smallInteger(), tinyInteger() adds support for MSSQL: DATE, SMALLDATETIME, MONEY, SMALLMONEY, BIGINT, SMALLINT, TINYINT adds support for mysql: BIGINT UNSIGNED, BIGINT, INT UNSIGNED, MEDIUMINT UNSIGNED, MEDIUMINT, SMALLINT UNSIGNED, SMALLINT, TINYINT UNSIGNED, TINYINT --- TableDefinition.cfc | 78 ++++++++++++++++++++++++--------- adapters/MicrosoftSQLServer.cfc | 56 +++++++++-------------- adapters/MySQL.cfc | 36 ++++++++++++++- adapters/Oracle.cfc | 1 + adapters/PostgreSQL.cfc | 1 + adapters/SQLite.cfc | 1 + 6 files changed, 117 insertions(+), 56 deletions(-) diff --git a/TableDefinition.cfc b/TableDefinition.cfc index 93255f4..0975b01 100755 --- a/TableDefinition.cfc +++ b/TableDefinition.cfc @@ -34,7 +34,7 @@ - + @@ -68,8 +68,8 @@ - - + + var loc = {}; @@ -82,14 +82,13 @@ - + - var loc = {}; - arguments.columnType = "biginteger"; + arguments.columnType = "binary"; loc.iEnd = ListLen(arguments.columnNames); for (loc.i=1; loc.i <= loc.iEnd; loc.i++) { arguments.columnName = ListGetAt(arguments.columnNames,loc.i); @@ -99,13 +98,13 @@ - + var loc = {}; - arguments.columnType = "binary"; + arguments.columnType = "boolean"; loc.iEnd = ListLen(arguments.columnNames); for (loc.i=1; loc.i <= loc.iEnd; loc.i++) { arguments.columnName = ListGetAt(arguments.columnNames,loc.i); @@ -115,13 +114,13 @@ - + var loc = {}; - arguments.columnType = "boolean"; + arguments.columnType = "date"; loc.iEnd = ListLen(arguments.columnNames); for (loc.i=1; loc.i <= loc.iEnd; loc.i++) { arguments.columnName = ListGetAt(arguments.columnNames,loc.i); @@ -131,13 +130,14 @@ - + + var loc = {}; - arguments.columnType = "date"; + arguments.columnType = "datetime"; loc.iEnd = ListLen(arguments.columnNames); for (loc.i=1; loc.i <= loc.iEnd; loc.i++) { arguments.columnName = ListGetAt(arguments.columnNames,loc.i); @@ -146,14 +146,16 @@ - - + + + + var loc = {}; - arguments.columnType = "datetime"; + arguments.columnType = "decimal"; loc.iEnd = ListLen(arguments.columnNames); for (loc.i=1; loc.i <= loc.iEnd; loc.i++) { arguments.columnName = ListGetAt(arguments.columnNames,loc.i); @@ -163,15 +165,15 @@ - + - + var loc = {}; - arguments.columnType = "decimal"; + arguments.columnType = "money"; loc.iEnd = ListLen(arguments.columnNames); for (loc.i=1; loc.i <= loc.iEnd; loc.i++) { arguments.columnName = ListGetAt(arguments.columnNames,loc.i); @@ -199,7 +201,7 @@ - + @@ -214,9 +216,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/adapters/MicrosoftSQLServer.cfc b/adapters/MicrosoftSQLServer.cfc index 69f9c83..a5d9957 100755 --- a/adapters/MicrosoftSQLServer.cfc +++ b/adapters/MicrosoftSQLServer.cfc @@ -4,7 +4,7 @@ - + @@ -13,6 +13,7 @@ + @@ -205,40 +206,24 @@ - var sql = ''; - if(IsDefined("variables.sqlTypes") && structKeyExists(variables.sqlTypes,arguments.type)) { - if(IsStruct(variables.sqlTypes[arguments.type])) { - sql = variables.sqlTypes[arguments.type]['name']; - if(arguments.type == 'decimal') { - if(!StructKeyExists(arguments.options,'precision') && StructKeyExists(variables.sqlTypes[arguments.type],'precision')) { - arguments.options.precision = variables.sqlTypes[arguments.type]['precision']; - } - if(!StructKeyExists(arguments.options,'scale') && StructKeyExists(variables.sqlTypes[arguments.type],'scale')) { - arguments.options.scale = variables.sqlTypes[arguments.type]['scale']; - } - if(StructKeyExists(arguments.options,'precision')) { - if(StructKeyExists(arguments.options,'scale')) { - sql = sql & '(#arguments.options.precision#,#arguments.options.scale#)'; - } else { - sql = sql & '(#arguments.options.precision#)'; - } - } - } else if(arguments.type == 'integer') { - if(StructKeyExists(arguments.options,'limit')) { - sql = sql; - } - } else { - if(!StructKeyExists(arguments.options,'limit') && StructKeyExists(variables.sqlTypes[arguments.type],'limit')) { - arguments.options.limit = variables.sqlTypes[arguments.type]['limit']; - } - if(StructKeyExists(arguments.options,'limit')) { - sql = sql & '(#arguments.options.limit#)'; - } - } + var sql = ''; + if(arguments.type == 'DATETIME' AND StructKeyExists(arguments.options,'limit') AND arguments.options.limit IS 'SMALL') { + sql = 'SMALLDATETIME'; + } else if(arguments.type == 'DATETIME' AND StructKeyExists(arguments.options,'limit') AND isNumeric( arguments.options.limit )) { + sql = 'DATETIME2(#arguments.limit#)'; + } else if(arguments.type == 'MONEY' AND StructKeyExists(arguments.options,'limit') AND arguments.options.limit IS 'SMALL') { + sql = 'SMALLMONEY'; + } else if(arguments.type == 'INTEGER' AND StructKeyExists(arguments.options,'limit') AND arguments.options.limit IS 'BIG') { + sql = 'BIGINT'; + } else if(arguments.type == 'INTEGER' AND StructKeyExists(arguments.options,'limit') AND arguments.options.limit IS 'SMALL') { + sql = 'SMALLINT'; + } else if(arguments.type == 'INTEGER' AND StructKeyExists(arguments.options,'limit') AND arguments.options.limit IS 'TINY') { + sql = 'TINYINT'; + } else if(arguments.type == 'INTEGER' ) { + sql = 'INT'; } else { - sql = variables.sqlTypes[arguments.type]; + sql = super.typeToSQL( argumentCollection = arguments ); } - } @@ -273,11 +258,12 @@ if( len( loc.identityCol ) AND listFindNoCase( structKeyList( arguments.values ), loc.identityCol ) ) { loc.sql = "SET IDENTITY_INSERT #quoteTableName(LCase(arguments.table))# ON;" & chr(10) & loc.sql & ";" & chr(10) - & "SET IDENTITY_INSERT #quoteTableName(LCase(arguments.table))# OFF;" & chr(10) + & "SET IDENTITY_INSERT #quoteTableName(LCase(arguments.table))# OFF;" & chr(10); } - \ No newline at end of file + + diff --git a/adapters/MySQL.cfc b/adapters/MySQL.cfc index 50f7015..03f1c2c 100755 --- a/adapters/MySQL.cfc +++ b/adapters/MySQL.cfc @@ -1,7 +1,6 @@ - @@ -14,6 +13,7 @@ + @@ -74,4 +74,38 @@ + + + + + var sql = super.typeToSQL( argumentCollection = arguments ); + if(arguments.type == 'INTEGER' AND StructKeyExists(arguments.options,'limit') ) { + if(arguments.options.limit IS 'BIG') { + sql = 'BIGINT'; + } else if(arguments.options.limit IS 'BIG UNSIGNED') { + sql = 'BIGINT UNSIGNED'; + } else if(arguments.options.limit IS 'UNSIGNED') { + sql = 'INT UNSIGNED'; + } else if(arguments.options.limit IS 'MEDIUM UNSIGNED') { + sql = 'MEDIUMINT UNSIGNED'; + } else if(arguments.options.limit IS 'MEDIUM') { + sql = 'MEDIUMINT'; + } else if(arguments.options.limit IS 'SMALL UNSIGNED') { + sql = 'SMALLINT UNSIGNED'; + } else if(arguments.options.limit IS 'SMALL') { + sql = 'SMALLINT'; + } else if(arguments.options.limit IS 'TINY UNSIGNED') { + sql = 'TINYINT UNSIGNED'; + } else if(arguments.options.limit IS 'TINY') { + sql = 'TINYINT'; + } else if(isNumeric(arguments.options.limit)){ + sql = 'INT(#arguments.options.limit#)'; + } else { + sql = 'INT'; + } + } + + + + \ No newline at end of file diff --git a/adapters/Oracle.cfc b/adapters/Oracle.cfc index 63ab2bd..717e63c 100755 --- a/adapters/Oracle.cfc +++ b/adapters/Oracle.cfc @@ -16,6 +16,7 @@ + diff --git a/adapters/PostgreSQL.cfc b/adapters/PostgreSQL.cfc index b47707e..a2c6113 100755 --- a/adapters/PostgreSQL.cfc +++ b/adapters/PostgreSQL.cfc @@ -12,6 +12,7 @@ + diff --git a/adapters/SQLite.cfc b/adapters/SQLite.cfc index 290bcb5..bbe31e7 100755 --- a/adapters/SQLite.cfc +++ b/adapters/SQLite.cfc @@ -12,6 +12,7 @@ + From 4ceaf321444b177dccc190836857ed2762c2a45a Mon Sep 17 00:00:00 2001 From: Jordan Clark Date: Sun, 31 Mar 2013 19:43:13 -0700 Subject: [PATCH 07/17] added tests for new datatypes --- tests/20130328131405_identity_insert.cfc | 15 ++++++++++ tests/20130328140935_new_mssql_types.cfc | 23 +++++++++++++++ tests/20130328140940_new_mysql_types.cfc | 37 ++++++++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 tests/20130328131405_identity_insert.cfc create mode 100644 tests/20130328140935_new_mssql_types.cfc create mode 100644 tests/20130328140940_new_mysql_types.cfc diff --git a/tests/20130328131405_identity_insert.cfc b/tests/20130328131405_identity_insert.cfc new file mode 100644 index 0000000..7738a47 --- /dev/null +++ b/tests/20130328131405_identity_insert.cfc @@ -0,0 +1,15 @@ + + + + t = createTable(name='ident_insert',id=false); + t.primaryKey(name="pk",type="integer",autoIncrement=true); + t.change(true); + addRecord(table='ident_insert',pk='10'); + + + + + dropTable(name='ident_insert'); + + + diff --git a/tests/20130328140935_new_mssql_types.cfc b/tests/20130328140935_new_mssql_types.cfc new file mode 100644 index 0000000..7da0760 --- /dev/null +++ b/tests/20130328140935_new_mssql_types.cfc @@ -0,0 +1,23 @@ + + + + t = changeTable(name='mssql_types'); + t.tinyInteger("test_tinyint"); + t.smallInteger("test_smallint"); + t.integer("test_int"); + t.bigInteger("test_bigint"); + t.date(columnNames="test_date"); + t.datetime(columnNames="test_datetime"); + t.datetime(columnNames="test_smalldatetime",precision="small"); + t.money(columnNames="test_money"); + t.money(columnNames="test_smallmoney",precision="small"); + t.create(); + addRecord(table='mssql_types',test_tinyint=1,test_int=2,test_bigint=3,test_date=now(),test_datetime=now(),test_smalldatetime=now(),test_money=4.56,test_smallmoney=7.89 ); + + + + + dropTable(name='mssql_types'); + + + diff --git a/tests/20130328140940_new_mysql_types.cfc b/tests/20130328140940_new_mysql_types.cfc new file mode 100644 index 0000000..72203e9 --- /dev/null +++ b/tests/20130328140940_new_mysql_types.cfc @@ -0,0 +1,37 @@ + + + + t = changeTable(name='mysql_types'); + t.tinyInteger("test_tinyint1"); + t.tinyInteger("test_tinyint2", "unsigned"); + t.integer("test_tinyint3", "tiny unsigned"); + t.smallInteger("test_smallint1"); + t.smallInteger("test_smallint2", "unsigned"); + t.integer("test_smallint3", "small unsigned"); + t.mediumInteger("test_mediumint1"); + t.mediumInteger("test_mediumint2", "unsigned"); + t.integer("test_mediumint3", "medium unsigned"); + t.integer("test_int1"); + t.integer("test_int2", "unsigned"); + t.integer("test_int3", "int"); + t.integer("test_int4", "int unsigned"); + t.bigInteger("test_bigint1"); + t.bigInteger("test_bigint2", "unsigned"); + t.integer("test_bigint3", "big unsigned"); + t.create(); + addRecord(table='mysql_types' + ,test_tinyint1=1,test_tinyint2=2,test_tinyint3=3 + ,test_smallint1=1,test_smallint2=2,test_smallint3=3 + ,test_mediumint1=1,test_mediumint2=2,test_mediumint3=3 + ,test_int1=1,test_int2=2,test_int2=2,test_int3=3,test_int4=4 + ,test_bigint1=1,test_bigint2=2,test_bigint3=3 + + ); + + + + + dropTable(name='mysql_types'); + + + From 84ec4e60b310def80e57ef340173bbcc1b4ce526 Mon Sep 17 00:00:00 2001 From: Jordan Clark Date: Mon, 1 Apr 2013 18:23:05 -0700 Subject: [PATCH 08/17] Add support for column "encoding" used for string, text and char columns (only currently supports MSSQL & MySQL) Add CHAR() column type for fixed length columns MSSQL: CHAR, NCHAR, NVARCHAR, NTEXT MYSQL: Character encoding for char, string & text Oracle: CHAR PostgreSQL: CHARACTER --- TableDefinition.cfc | 25 ++++++++++++++-- adapters/MicrosoftSQLServer.cfc | 43 ++++++++++++++-------------- adapters/MySQL.cfc | 8 ++++-- adapters/Oracle.cfc | 1 + adapters/PostgreSQL.cfc | 1 + adapters/SQLite.cfc | 1 + tests/20130401140940_new_strings.cfc | 28 ++++++++++++++++++ 7 files changed, 82 insertions(+), 25 deletions(-) create mode 100644 tests/20130401140940_new_strings.cfc diff --git a/TableDefinition.cfc b/TableDefinition.cfc index 0975b01..a5923d3 100755 --- a/TableDefinition.cfc +++ b/TableDefinition.cfc @@ -71,12 +71,13 @@ + var loc = {}; arguments.adapter = this.adapter; arguments.name = arguments.columnName; arguments.type = arguments.columnType; - loc.column = CreateObject("component","ColumnDefinition").init(argumentCollection=arguments); + loc.column = createObject("component","ColumnDefinition").init(argumentCollection=arguments); ArrayAppend(this.columns,loc.column); @@ -250,13 +251,14 @@ - + + var loc = {}; arguments.columnType = "string"; @@ -269,10 +271,29 @@ + + + + + + + + var loc = {}; + arguments.columnType = "char"; + loc.iEnd = ListLen(arguments.columnNames); + for (loc.i=1; loc.i <= loc.iEnd; loc.i++) { + arguments.columnName = ListGetAt(arguments.columnNames,loc.i); + column(argumentCollection=arguments); + } + + + + + var loc = {}; arguments.columnType = "text"; diff --git a/adapters/MicrosoftSQLServer.cfc b/adapters/MicrosoftSQLServer.cfc index a5d9957..43b0c23 100755 --- a/adapters/MicrosoftSQLServer.cfc +++ b/adapters/MicrosoftSQLServer.cfc @@ -10,6 +10,7 @@ + @@ -41,17 +42,17 @@ var loc = {}; - - loc.sql = "CONSTRAINT [PK_#arguments.name#] PRIMARY KEY CLUSTERED ("; - - for (loc.i = 1; loc.i lte ArrayLen(arguments.primaryKeys); loc.i++) - { - if (loc.i != 1) - loc.sql = loc.sql & ", "; - loc.sql = loc.sql & arguments.primaryKeys[loc.i].toColumnNameSQL() & " ASC"; - } - - loc.sql = loc.sql & ")"; + + loc.sql = "CONSTRAINT [PK_#arguments.name#] PRIMARY KEY CLUSTERED ("; + + for (loc.i = 1; loc.i lte ArrayLen(arguments.primaryKeys); loc.i++) + { + if (loc.i != 1) + loc.sql = loc.sql & ", "; + loc.sql = loc.sql & arguments.primaryKeys[loc.i].toColumnNameSQL() & " ASC"; + } + + loc.sql = loc.sql & ")"; @@ -206,23 +207,23 @@ - var sql = ''; - if(arguments.type == 'DATETIME' AND StructKeyExists(arguments.options,'limit') AND arguments.options.limit IS 'SMALL') { + var sql = super.typeToSQL( argumentCollection = arguments ); + if(arguments.type IS 'DATETIME' AND StructKeyExists(arguments.options,'limit') AND arguments.options.limit IS 'SMALL') { sql = 'SMALLDATETIME'; - } else if(arguments.type == 'DATETIME' AND StructKeyExists(arguments.options,'limit') AND isNumeric( arguments.options.limit )) { + } else if(arguments.type IS 'DATETIME' AND StructKeyExists(arguments.options,'limit') AND isNumeric( arguments.options.limit )) { sql = 'DATETIME2(#arguments.limit#)'; - } else if(arguments.type == 'MONEY' AND StructKeyExists(arguments.options,'limit') AND arguments.options.limit IS 'SMALL') { + } else if(arguments.type IS 'MONEY' AND StructKeyExists(arguments.options,'limit') AND arguments.options.limit IS 'SMALL') { sql = 'SMALLMONEY'; - } else if(arguments.type == 'INTEGER' AND StructKeyExists(arguments.options,'limit') AND arguments.options.limit IS 'BIG') { + } else if(arguments.type IS 'INTEGER' AND StructKeyExists(arguments.options,'limit') AND arguments.options.limit IS 'BIG') { sql = 'BIGINT'; - } else if(arguments.type == 'INTEGER' AND StructKeyExists(arguments.options,'limit') AND arguments.options.limit IS 'SMALL') { + } else if(arguments.type IS 'INTEGER' AND StructKeyExists(arguments.options,'limit') AND arguments.options.limit IS 'SMALL') { sql = 'SMALLINT'; - } else if(arguments.type == 'INTEGER' AND StructKeyExists(arguments.options,'limit') AND arguments.options.limit IS 'TINY') { + } else if(arguments.type IS 'INTEGER' AND StructKeyExists(arguments.options,'limit') AND arguments.options.limit IS 'TINY') { sql = 'TINYINT'; - } else if(arguments.type == 'INTEGER' ) { + } else if(arguments.type IS 'INTEGER' ) { sql = 'INT'; - } else { - sql = super.typeToSQL( argumentCollection = arguments ); + } else if(listFindNoCase('CHAR,STRING,TEXT', arguments.type) AND structKeyExists(arguments.options,'encoding') AND listFindNoCase( "utf8,unicode", arguments.options.encoding ) ) { + sql = 'N' & sql; // for NCHAR, NVARCHAR, NTEXT } diff --git a/adapters/MySQL.cfc b/adapters/MySQL.cfc index 03f1c2c..0dba76e 100755 --- a/adapters/MySQL.cfc +++ b/adapters/MySQL.cfc @@ -9,6 +9,7 @@ + @@ -100,9 +101,12 @@ sql = 'TINYINT'; } else if(isNumeric(arguments.options.limit)){ sql = 'INT(#arguments.options.limit#)'; - } else { - sql = 'INT'; } + } else if(listFindNoCase( 'CHAR,STRING,TEXT', arguments.type ) AND structKeyExists(arguments.options,'encoding') AND len( arguments.options.encoding ) ) { + if( arguments.options.encoding IS "unicode" ) { + arguments.options.encoding = "utf8"; + } + sql = sql & ' CHARACTER SET #arguments.options.encoding#';, } diff --git a/adapters/Oracle.cfc b/adapters/Oracle.cfc index 717e63c..8f6599e 100755 --- a/adapters/Oracle.cfc +++ b/adapters/Oracle.cfc @@ -13,6 +13,7 @@ + diff --git a/adapters/PostgreSQL.cfc b/adapters/PostgreSQL.cfc index a2c6113..142569d 100755 --- a/adapters/PostgreSQL.cfc +++ b/adapters/PostgreSQL.cfc @@ -9,6 +9,7 @@ + diff --git a/adapters/SQLite.cfc b/adapters/SQLite.cfc index bbe31e7..9c2989b 100755 --- a/adapters/SQLite.cfc +++ b/adapters/SQLite.cfc @@ -9,6 +9,7 @@ + diff --git a/tests/20130401140940_new_strings.cfc b/tests/20130401140940_new_strings.cfc new file mode 100644 index 0000000..8ccee74 --- /dev/null +++ b/tests/20130401140940_new_strings.cfc @@ -0,0 +1,28 @@ + + + + t = changeTable(name='string_types'); + t.char("char_none"); + t.char(columnNames="char_ascii",encoding="ascii"); + t.char(columnNames="char_unicode",encoding="unicode"); + t.column(columnName="char_column",columnType="string",encoding="utf8"); + + t.string("varchar_none"); + t.string(columnNames="varchar_ascii",encoding="ascii"); + t.string(columnNames="varchar_unicode",encoding="unicode"); + t.column(columnName="varchar_column",columnType="string",encoding="utf8"); + + t.text("text_none"); + t.text(columnNames="text_ascii",encoding="ascii"); + t.text(columnNames="text_unicode",encoding="unicode"); + t.column(columnName="text_column",columnType="string",encoding="utf8"); + + t.create(); + + + + + dropTable(name='string_types'); + + + From 7ef572078b1e9fcd59b213686a9cff61f1996346 Mon Sep 17 00:00:00 2001 From: Jordan Clark Date: Tue, 2 Apr 2013 08:52:33 -0700 Subject: [PATCH 09/17] change mysql boolean to BIT (resolves andybellenie's issue #57) --- adapters/MySQL.cfc | 2 +- tests/20130402140940_mysql_bit.cfc | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/20130402140940_mysql_bit.cfc diff --git a/adapters/MySQL.cfc b/adapters/MySQL.cfc index 0dba76e..5310b92 100755 --- a/adapters/MySQL.cfc +++ b/adapters/MySQL.cfc @@ -2,7 +2,7 @@ - + diff --git a/tests/20130402140940_mysql_bit.cfc b/tests/20130402140940_mysql_bit.cfc new file mode 100644 index 0000000..99cec6a --- /dev/null +++ b/tests/20130402140940_mysql_bit.cfc @@ -0,0 +1,16 @@ + + + + t = changeTable(name='mysql_bit'); + t.boolean("foo"); + t.create(); + addRecord(table='mysql_bit',foo=true); + addRecord(table='mysql_bit',foo=false); + + + + + dropTable(name='mysql_bit'); + + + From ab6e82592efef93058e87b6fe91637a1ee86c78e Mon Sep 17 00:00:00 2001 From: Jordan Clark Date: Tue, 2 Apr 2013 09:13:14 -0700 Subject: [PATCH 10/17] added the ability to pre-fill table name into the templates --- dbmigrate.cfc | 4 ++++ index.cfm | 7 ++++++- templates/change-column.cfc | 4 ++-- templates/change-table.cfc | 4 ++-- templates/create-column.cfc | 4 ++-- templates/create-index.cfc | 4 ++-- templates/create-record.cfc | 4 ++-- templates/create-table.cfc | 4 ++-- templates/remove-column.cfc | 4 ++-- templates/remove-index.cfc | 4 ++-- templates/remove-record.cfc | 4 ++-- templates/remove-table.cfc | 4 ++-- templates/rename-column.cfc | 4 ++-- templates/update-record.cfc | 4 ++-- 14 files changed, 34 insertions(+), 25 deletions(-) diff --git a/dbmigrate.cfc b/dbmigrate.cfc index a341c5d..f354448 100644 --- a/dbmigrate.cfc +++ b/dbmigrate.cfc @@ -121,6 +121,7 @@ + @@ -162,6 +163,8 @@ + + @@ -181,6 +184,7 @@ + diff --git a/index.cfm b/index.cfm index f6b3282..b60fd58 100644 --- a/index.cfm +++ b/index.cfm @@ -11,7 +11,8 @@ - + + @@ -117,6 +118,10 @@ +
+ + +

diff --git a/templates/change-column.cfc b/templates/change-column.cfc index a7e7692..d304d69 100644 --- a/templates/change-column.cfc +++ b/templates/change-column.cfc @@ -20,12 +20,12 @@ - changeColumn(table='tableName', columnType='', columnName='columnName', default='', null=true); + changeColumn(table='[tableName]', columnType='', columnName='columnName', default='', null=true); - changeColumn(table='tableName',columnName='columnName'); + changeColumn(table='[tableName]',columnName='columnName'); \ No newline at end of file diff --git a/templates/change-table.cfc b/templates/change-table.cfc index 481a55c..411577a 100644 --- a/templates/change-table.cfc +++ b/templates/change-table.cfc @@ -13,14 +13,14 @@ - t = changeTable('tableName'); + t = changeTable('[tableName]'); t.change(); - removeColumn(table='tableName',columnName='columnName'); + removeColumn(table='[tableName]',columnName='columnName'); \ No newline at end of file diff --git a/templates/create-column.cfc b/templates/create-column.cfc index 06cb614..0a4168a 100644 --- a/templates/create-column.cfc +++ b/templates/create-column.cfc @@ -19,12 +19,12 @@ - addColumn(table='tableName', columnType='', columnName='columnName', default='', null=true); + addColumn(table='[tableName]', columnType='', columnName='columnName', default='', null=true); - removeColumn(table='tableName',columnName='columnName'); + removeColumn(table='[tableName]',columnName='columnName'); \ No newline at end of file diff --git a/templates/create-index.cfc b/templates/create-index.cfc index 8ce0f92..116da38 100644 --- a/templates/create-index.cfc +++ b/templates/create-index.cfc @@ -14,12 +14,12 @@ - addIndex(table='tableName',columnNames='columnName',unique=true); + addIndex(table='[tableName]',columnNames='columnName',unique=true); - removeIndex(table='tableName', indexName=''); + removeIndex(table='[tableName]', indexName=''); \ No newline at end of file diff --git a/templates/create-record.cfc b/templates/create-record.cfc index 4486592..eee63f2 100644 --- a/templates/create-record.cfc +++ b/templates/create-record.cfc @@ -12,12 +12,12 @@ - addRecord(table='tableName',field=''); + addRecord(table='[tableName]',field=''); - removeRecord(table='tableName',where=''); + removeRecord(table='[tableName]',where=''); \ No newline at end of file diff --git a/templates/create-table.cfc b/templates/create-table.cfc index d0e9c15..6af1238 100644 --- a/templates/create-table.cfc +++ b/templates/create-table.cfc @@ -21,7 +21,7 @@ - t = createTable(name='tableName'); + t = createTable(name='[tableName]'); t.timestamps(); t.create(); @@ -29,7 +29,7 @@ - dropTable('tableName'); + dropTable('[tableName]'); \ No newline at end of file diff --git a/templates/remove-column.cfc b/templates/remove-column.cfc index 1f665a4..bd494f0 100644 --- a/templates/remove-column.cfc +++ b/templates/remove-column.cfc @@ -13,12 +13,12 @@ - removeColumn(table='tableName',columnName='columnName'); + removeColumn(table='[tableName]',columnName='columnName'); - addColumn(table='tableName', columnType='', columnName='columnName', default='', null=true); + addColumn(table='[tableName]', columnType='', columnName='columnName', default='', null=true); \ No newline at end of file diff --git a/templates/remove-index.cfc b/templates/remove-index.cfc index 6915fb2..6557ed1 100644 --- a/templates/remove-index.cfc +++ b/templates/remove-index.cfc @@ -12,12 +12,12 @@ - removeIndex(table='tableName', indexName=''); + removeIndex(table='[tableName]', indexName=''); - addIndex(table='tableName',columnNames='columnName',unique=true); + addIndex(table='[tableName]',columnNames='columnName',unique=true); \ No newline at end of file diff --git a/templates/remove-record.cfc b/templates/remove-record.cfc index f00659c..57c882c 100644 --- a/templates/remove-record.cfc +++ b/templates/remove-record.cfc @@ -12,12 +12,12 @@ - removeRecord(table='tableName',where=''); + removeRecord(table='[tableName]',where=''); - addRecord(table='tableName',field=''); + addRecord(table='[tableName]',field=''); \ No newline at end of file diff --git a/templates/remove-table.cfc b/templates/remove-table.cfc index 484ef2a..76660bb 100644 --- a/templates/remove-table.cfc +++ b/templates/remove-table.cfc @@ -11,12 +11,12 @@ - dropTable(name='tableName'); + dropTable(name='[tableName]'); - t = createTable(name='tableName'); + t = createTable(name='[tableName]'); t.timestamps(); t.create(); diff --git a/templates/rename-column.cfc b/templates/rename-column.cfc index 4a105fa..e9f5185 100644 --- a/templates/rename-column.cfc +++ b/templates/rename-column.cfc @@ -13,12 +13,12 @@ - renameColumn(table='tableName', columnName='columnName', newColumnName='newColumnName'); + renameColumn(table='[tableName]', columnName='columnName', newColumnName='newColumnName'); - renameColumn(table='tableName', columnName='columnName', newColumnName='newColumnName'); + renameColumn(table='[tableName]', columnName='columnName', newColumnName='newColumnName'); \ No newline at end of file diff --git a/templates/update-record.cfc b/templates/update-record.cfc index 6b2eee2..07405d0 100644 --- a/templates/update-record.cfc +++ b/templates/update-record.cfc @@ -13,12 +13,12 @@ - updateRecord(table='tableName',where=''); + updateRecord(table='[tableName]',where=''); - updateRecord(table='tableName',where=''); + updateRecord(table='[tableName]',where=''); \ No newline at end of file From 8cbd647b2b39675f0a079ce4d6b424d925756460 Mon Sep 17 00:00:00 2001 From: Jordan Clark Date: Tue, 2 Apr 2013 09:33:39 -0700 Subject: [PATCH 11/17] fix test --- tests/20130328140935_new_mssql_types.cfc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/20130328140935_new_mssql_types.cfc b/tests/20130328140935_new_mssql_types.cfc index 7da0760..a6fec89 100644 --- a/tests/20130328140935_new_mssql_types.cfc +++ b/tests/20130328140935_new_mssql_types.cfc @@ -8,9 +8,9 @@ t.bigInteger("test_bigint"); t.date(columnNames="test_date"); t.datetime(columnNames="test_datetime"); - t.datetime(columnNames="test_smalldatetime",precision="small"); + t.datetime(columnNames="test_smalldatetime",limit="small"); t.money(columnNames="test_money"); - t.money(columnNames="test_smallmoney",precision="small"); + t.money(columnNames="test_smallmoney",limit="small"); t.create(); addRecord(table='mssql_types',test_tinyint=1,test_int=2,test_bigint=3,test_date=now(),test_datetime=now(),test_smalldatetime=now(),test_money=4.56,test_smallmoney=7.89 ); From 0a31697b286c7b711d73bafae57c4aec4e7df688 Mon Sep 17 00:00:00 2001 From: Jordan Clark Date: Tue, 2 Apr 2013 09:34:57 -0700 Subject: [PATCH 12/17] update the version, support table name pre-filling --- index.cfm | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/index.cfm b/index.cfm index b60fd58..91d5c72 100644 --- a/index.cfm +++ b/index.cfm @@ -1,7 +1,7 @@ - + @@ -114,16 +114,16 @@
-
+
+ + +
+
-
- - -
-
+
From aec5f5a0e78d07583350331569060830d3e71cbc Mon Sep 17 00:00:00 2001 From: Jordan Clark Date: Tue, 2 Apr 2013 10:24:24 -0700 Subject: [PATCH 13/17] Moved updateRecord/removeRecord SQL building into abstract adapter to allow overriding. Added NULL support to addRecord/updateRecord. Added automatic timestamp support for createdAt/updatedAt and soft-delete deletedAt --- Migration.cfc | 32 +++----- adapters/Abstract.cfc | 76 ++++++++++++++++++- basefunctions.cfm | 2 +- tests/20130328140935_new_mssql_types.cfc | 2 +- tests/20130328140940_new_mysql_types.cfc | 2 +- tests/20130401140940_new_strings.cfc | 2 +- tests/20130402140940_mysql_bit.cfc | 3 +- tests/20130402141040_test_timestamps.cfc | 19 +++++ ...2141043_test_insert_update_null_values.cfc | 19 +++++ 9 files changed, 129 insertions(+), 28 deletions(-) create mode 100644 tests/20130402141040_test_timestamps.cfc create mode 100644 tests/20130402141043_test_insert_update_null_values.cfc diff --git a/Migration.cfc b/Migration.cfc index 73300e6..fb5ca8b 100644 --- a/Migration.cfc +++ b/Migration.cfc @@ -214,55 +214,43 @@
+ var loc = {}; - loc.columnUpdates = ""; + loc.values = {}; for (loc.key in arguments) { - if(loc.key neq "table" && loc.key neq "where") { - loc.update = "#this.adapter.quoteColumnName(loc.key)# = "; - if(IsNumeric(arguments[loc.key])) { - loc.update = loc.update & "#arguments[loc.key]#"; - } else if(IsBoolean(arguments[loc.key])) { - loc.update = loc.update & "#IIf(arguments[loc.key],1,0)#"; - } else if(IsDate(arguments[loc.key])) { - loc.update = loc.update & "#arguments[loc.key]#"; - } else { - arguments[loc.key] = ReplaceNoCase(arguments[loc.key], "'", "''", "all"); - loc.update = loc.update & "'#arguments[loc.key]#'"; - } - loc.columnUpdates = ListAppend(loc.columnUpdates,loc.update); + if(loc.key neq "table" AND loc.key neq "where") { + loc.values[ loc.key ] = arguments[ loc.key ]; } } - if(loc.columnUpdates != '') { - loc.sql = 'UPDATE #this.adapter.quoteTableName(LCase(arguments.table))# SET #loc.columnUpdates#'; + if( NOT structIsEmpty( loc.values ) ) { + $execute( this.adapter.updateRecord( arguments.table, arguments.where, loc.values ) ); loc.message = 'Updated record(s) in table #arguments.table#'; if(arguments.where != '') { - loc.sql = loc.sql & ' WHERE #arguments.where#'; loc.message = loc.message & ' where #arguments.where#'; } - $execute(loc.sql); announce(loc.message); } + var loc = {}; - loc.sql = 'DELETE FROM #this.adapter.quoteTableName(LCase(arguments.table))#'; + $execute( this.adapter.removeRecord( arguments.table, arguments.where ) ); loc.message = 'Removed record(s) from table #arguments.table#'; if(arguments.where != '') { - loc.sql = loc.sql & ' WHERE #arguments.where#'; loc.message = loc.message & ' where #arguments.where#'; } - $execute(loc.sql); announce(loc.message); - + + diff --git a/adapters/Abstract.cfc b/adapters/Abstract.cfc index 5a259b6..841ccd8 100755 --- a/adapters/Abstract.cfc +++ b/adapters/Abstract.cfc @@ -286,12 +286,24 @@ var loc = {}; + loc.columnNames = $getColumns( arguments.table ); + // pre-fill createdAt column + if( NOT structKeyExists( arguments.values, "createdAt" ) AND listFindNoCase( loc.columnNames, "createdAt" ) ) { + arguments.values.createdAt = now(); + } + // pre-fill updatedAt column + if( NOT structKeyExists( arguments.values, "updatedAt" ) AND listFindNoCase( loc.columnNames, "updatedAt" ) ) { + arguments.values.updatedAt = now(); + } + loc.sql = ""; loc.columnNames = ""; loc.columnValues = ""; for (loc.key in arguments.values) { loc.columnNames = ListAppend(loc.columnNames,quoteColumnName(loc.key)); - if(IsNumeric(arguments.values[loc.key])) { + if(arguments.values[loc.key] IS "NULL") { + loc.columnValues = ListAppend(loc.columnValues,arguments.values[loc.key]); + } else if(IsNumeric(arguments.values[loc.key])) { loc.columnValues = ListAppend(loc.columnValues,arguments.values[loc.key]); } else if(IsBoolean(arguments.values[loc.key])) { loc.columnValues = ListAppend(loc.columnValues,IIf(arguments.values[loc.key],1,0)); @@ -307,4 +319,66 @@ + + + + + + + var loc = {}; + loc.columnNames = $getColumns( arguments.table ); + // pre-fill updatedAt column + if( NOT structKeyExists( arguments.values, "updatedAt" ) AND listFindNoCase( loc.columnNames, "updatedAt" ) ) { + arguments.values.updatedAt = now(); + } + + loc.columnUpdates = ""; + for (loc.key in arguments.values) { + loc.update = "#quoteColumnName(loc.key)# = "; + if(arguments.values[loc.key] IS "NULL") { + loc.update = loc.update & arguments.values[loc.key]; + } else if(IsNumeric(arguments.values[loc.key])) { + loc.update = loc.update & "#arguments.values[loc.key]#"; + } else if(IsBoolean(arguments.values[loc.key])) { + loc.update = loc.update & "#IIf(arguments.values[loc.key],1,0)#"; + } else if(IsDate(arguments.values[loc.key])) { + loc.update = loc.update & "#arguments.values[loc.key]#"; + } else { + arguments.values[loc.key] = ReplaceNoCase(arguments.values[loc.key], "'", "''", "all"); + loc.update = loc.update & "'#arguments.values[loc.key]#'"; + } + loc.columnUpdates = ListAppend(loc.columnUpdates,loc.update); + } + if(loc.columnUpdates != '') { + loc.sql = 'UPDATE #quoteTableName(LCase(arguments.table))# SET #loc.columnUpdates#'; + if(arguments.where != '') { + loc.sql = loc.sql & ' WHERE #arguments.where#'; + } + $execute(loc.sql); + } + + + + + + + + + var loc = {}; + loc.columnNames = $getColumns( arguments.table ); + // pre-fill deleteAt column for a "soft-delete" + if( listFindNoCase( loc.columnNames, "deletedAt" ) ) { + loc.values = {}; + loc.values.deletedAt = now(); + updateRecord( arguments.table, arguments.where, loc.values ); + } else { + loc.sql = 'DELETE FROM #quoteTableName(LCase(arguments.table))#'; + if(arguments.where != '') { + loc.sql = loc.sql & ' WHERE #arguments.where#'; + } + $execute(loc.sql); + } + + + \ No newline at end of file diff --git a/basefunctions.cfm b/basefunctions.cfm index 56948ba..737db10 100755 --- a/basefunctions.cfm +++ b/basefunctions.cfm @@ -106,4 +106,4 @@ } - + \ No newline at end of file diff --git a/tests/20130328140935_new_mssql_types.cfc b/tests/20130328140935_new_mssql_types.cfc index a6fec89..99ab881 100644 --- a/tests/20130328140935_new_mssql_types.cfc +++ b/tests/20130328140935_new_mssql_types.cfc @@ -1,7 +1,7 @@ - t = changeTable(name='mssql_types'); + t = createTable(name='mssql_types'); t.tinyInteger("test_tinyint"); t.smallInteger("test_smallint"); t.integer("test_int"); diff --git a/tests/20130328140940_new_mysql_types.cfc b/tests/20130328140940_new_mysql_types.cfc index 72203e9..9cbbffc 100644 --- a/tests/20130328140940_new_mysql_types.cfc +++ b/tests/20130328140940_new_mysql_types.cfc @@ -1,7 +1,7 @@ - t = changeTable(name='mysql_types'); + t = createTable(name='mysql_types'); t.tinyInteger("test_tinyint1"); t.tinyInteger("test_tinyint2", "unsigned"); t.integer("test_tinyint3", "tiny unsigned"); diff --git a/tests/20130401140940_new_strings.cfc b/tests/20130401140940_new_strings.cfc index 8ccee74..8613633 100644 --- a/tests/20130401140940_new_strings.cfc +++ b/tests/20130401140940_new_strings.cfc @@ -1,7 +1,7 @@ - t = changeTable(name='string_types'); + t = createTable(name='string_types'); t.char("char_none"); t.char(columnNames="char_ascii",encoding="ascii"); t.char(columnNames="char_unicode",encoding="unicode"); diff --git a/tests/20130402140940_mysql_bit.cfc b/tests/20130402140940_mysql_bit.cfc index 99cec6a..e8d7ba5 100644 --- a/tests/20130402140940_mysql_bit.cfc +++ b/tests/20130402140940_mysql_bit.cfc @@ -1,9 +1,10 @@ - t = changeTable(name='mysql_bit'); + t = createTable(name='mysql_bit'); t.boolean("foo"); t.create(); + addRecord(table='mysql_bit',foo=true); addRecord(table='mysql_bit',foo=false); diff --git a/tests/20130402141040_test_timestamps.cfc b/tests/20130402141040_test_timestamps.cfc new file mode 100644 index 0000000..e19928c --- /dev/null +++ b/tests/20130402141040_test_timestamps.cfc @@ -0,0 +1,19 @@ + + + + t = createTable(name='test_timestamps'); + t.string("label"); + t.timestamps(); + t.create(); + + addRecord(table='test_timestamps',label="Foo"); + addRecord(table='test_timestamps',label="Bar"); + updateRecord(table='test_timestamps',where="label='Bar'",label="Bar2"); + + + + + dropTable(name='test_timestamps'); + + + diff --git a/tests/20130402141043_test_insert_update_null_values.cfc b/tests/20130402141043_test_insert_update_null_values.cfc new file mode 100644 index 0000000..bb6ba6a --- /dev/null +++ b/tests/20130402141043_test_insert_update_null_values.cfc @@ -0,0 +1,19 @@ + + + + t = createTable(name='test_null'); + t.string("label",50,"",false,"unicode"); + t.string("email",50,"null",true,"unicode"); + t.create(); + + addRecord(table="test_null",label="Foo",email="foo@foo.com"); + addRecord(table="test_null",label="Bar"); + addRecord(table="test_null",label="Snork",email="NULL"); + + + + + dropTable('test_null'); + + + From a2494729f21ae788c4b945912f983e729651f0e4 Mon Sep 17 00:00:00 2001 From: Jordan Clark Date: Tue, 2 Apr 2013 10:49:00 -0700 Subject: [PATCH 14/17] Updated to remove forcing table names to lowercase for all adapters. Instead the quoteTableName() method is the perfect place to force lower case for mysql, and let the other adapters decide what they want to do in their own quoteTableName(). Apparently postgress & oracle don't require quoting names, because if you do the name becomes case-sensitive, so now those adapters check if the name needs to be quoted instead of always doing it. Also fixes issue #43 for quoting postgres table names. --- adapters/Abstract.cfc | 24 ++++++++++++------------ adapters/MicrosoftSQLServer.cfc | 24 ++++++++++++------------ adapters/MySQL.cfc | 6 +++--- adapters/Oracle.cfc | 16 ++++++++++++---- adapters/PostgreSQL.cfc | 11 +++++++++-- 5 files changed, 48 insertions(+), 33 deletions(-) diff --git a/adapters/Abstract.cfc b/adapters/Abstract.cfc index 841ccd8..506ae30 100755 --- a/adapters/Abstract.cfc +++ b/adapters/Abstract.cfc @@ -132,7 +132,7 @@ var loc = {}; - loc.sql = "CREATE TABLE #quoteTableName(LCase(arguments.name))# (#chr(13)##chr(10)#"; + loc.sql = "CREATE TABLE #quoteTableName(arguments.name)# (#chr(13)##chr(10)#"; loc.iEnd = ArrayLen(arguments.primaryKeys); @@ -180,44 +180,44 @@ - + - + - + - + - + - + - + @@ -230,7 +230,7 @@ - var loc = { sql = "CONSTRAINT #quoteTableName(arguments.name)# FOREIGN KEY (#quoteColumnName(arguments.column)#) REFERENCES #LCase(arguments.referenceTable)#(#quoteColumnName(arguments.referenceColumn)#)" }; + var loc = { sql = "CONSTRAINT #quoteTableName(arguments.name)# FOREIGN KEY (#quoteColumnName(arguments.column)#) REFERENCES #quoteTableName(arguments.referenceTable)#(#quoteColumnName(arguments.referenceColumn)#)" }; for (loc.item in listToArray("onUpdate,onDelete")) { if (len(arguments[loc.item])) @@ -313,7 +313,7 @@ loc.columnValues = ListAppend(loc.columnValues,"'#ReplaceNoCase(arguments.values[loc.key],"'","''","all")#'"); } } - loc.sql = "INSERT INTO #quoteTableName(LCase(arguments.table))# ( #loc.columnNames# ) VALUES ( #loc.columnValues# )"; + loc.sql = "INSERT INTO #quoteTableName(arguments.table)# ( #loc.columnNames# ) VALUES ( #loc.columnValues# )"; @@ -350,7 +350,7 @@ loc.columnUpdates = ListAppend(loc.columnUpdates,loc.update); } if(loc.columnUpdates != '') { - loc.sql = 'UPDATE #quoteTableName(LCase(arguments.table))# SET #loc.columnUpdates#'; + loc.sql = 'UPDATE #quoteTableName(arguments.table)# SET #loc.columnUpdates#'; if(arguments.where != '') { loc.sql = loc.sql & ' WHERE #arguments.where#'; } @@ -372,7 +372,7 @@ loc.values.deletedAt = now(); updateRecord( arguments.table, arguments.where, loc.values ); } else { - loc.sql = 'DELETE FROM #quoteTableName(LCase(arguments.table))#'; + loc.sql = 'DELETE FROM #quoteTableName(arguments.table)#'; if(arguments.where != '') { loc.sql = loc.sql & ' WHERE #arguments.where#'; } diff --git a/adapters/MicrosoftSQLServer.cfc b/adapters/MicrosoftSQLServer.cfc index 43b0c23..2dde6f1 100755 --- a/adapters/MicrosoftSQLServer.cfc +++ b/adapters/MicrosoftSQLServer.cfc @@ -60,7 +60,7 @@ - + @@ -78,26 +78,26 @@ - + - + - + - + @@ -106,7 +106,7 @@ - + @@ -114,7 +114,7 @@ - + @@ -144,7 +144,7 @@ - + @@ -154,7 +154,7 @@ - EXEC sp_helpconstraint #quoteTableName(LCase(arguments.name))#, 'nomsg' + EXEC sp_helpconstraint #quoteTableName(arguments.name)#, 'nomsg' @@ -167,7 +167,7 @@ - + @@ -257,9 +257,9 @@ // if trying to insert into an identity column wrap it with IDENTITY_INSERT ON/OFF if( len( loc.identityCol ) AND listFindNoCase( structKeyList( arguments.values ), loc.identityCol ) ) { - loc.sql = "SET IDENTITY_INSERT #quoteTableName(LCase(arguments.table))# ON;" & chr(10) + loc.sql = "SET IDENTITY_INSERT #quoteTableName(arguments.table)# ON;" & chr(10) & loc.sql & ";" & chr(10) - & "SET IDENTITY_INSERT #quoteTableName(LCase(arguments.table))# OFF;" & chr(10); + & "SET IDENTITY_INSERT #quoteTableName(arguments.table)# OFF;" & chr(10); } diff --git a/adapters/MySQL.cfc b/adapters/MySQL.cfc index 5310b92..5c66139 100755 --- a/adapters/MySQL.cfc +++ b/adapters/MySQL.cfc @@ -37,10 +37,10 @@ - + - + @@ -65,7 +65,7 @@ - + diff --git a/adapters/Oracle.cfc b/adapters/Oracle.cfc index 8f6599e..3e9f3e7 100755 --- a/adapters/Oracle.cfc +++ b/adapters/Oracle.cfc @@ -23,6 +23,14 @@ + + + + + + + + @@ -101,19 +109,19 @@ announce("Dropped sequence #arguments.name#_seq"); - + - + - + @@ -125,7 +133,7 @@ - + diff --git a/adapters/PostgreSQL.cfc b/adapters/PostgreSQL.cfc index 142569d..9ed5d30 100755 --- a/adapters/PostgreSQL.cfc +++ b/adapters/PostgreSQL.cfc @@ -31,7 +31,14 @@ - + + + + + + + + @@ -62,7 +69,7 @@ - + From 0812e9b6d3e726b7bc522a260cc52d035ea80525 Mon Sep 17 00:00:00 2001 From: Jordan Clark Date: Thu, 18 Apr 2013 18:33:55 -0700 Subject: [PATCH 15/17] re-fix the railo createObjectFromRoot --- dbmigrate.cfc | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/dbmigrate.cfc b/dbmigrate.cfc index f354448..d2c3803 100644 --- a/dbmigrate.cfc +++ b/dbmigrate.cfc @@ -100,7 +100,7 @@ - + @@ -109,8 +109,8 @@ - - + + @@ -150,10 +150,18 @@ var loc = {}; - arguments.returnVariable = "loc.returnValue"; - arguments.component = arguments.path & "." & arguments.fileName; - StructDelete(arguments, "path"); - StructDelete(arguments, "fileName"); + loc.returnValue = ""; + if( listFind( "1.0,1.0.1,1.0.2,1.0.3,1.0.4,1.0.5,1.1,1.1.3,1.1.4,1.1.5,1.1.6,1.1.7,1.1.8", application.wheels.version ) ) { + arguments.returnVariable = "loc.returnValue"; + arguments.component = arguments.path & "." & arguments.fileName; + StructDelete(arguments, "path"); + StructDelete(arguments, "fileName"); + } else { // 1.1.9 fix + loc.returnVariable = "loc.returnValue"; + loc.method = arguments.method; + loc.component = ListChangeDelims(arguments.path, ".", "/") & "." & ListChangeDelims(arguments.fileName, ".", "/"); + loc.argumentCollection = arguments; + } From badd48afc6184c4701b45c3ee1b644feffcb59eb Mon Sep 17 00:00:00 2001 From: Jordan Clark Date: Thu, 4 Jul 2013 16:32:11 -0700 Subject: [PATCH 16/17] Fix incorrect variable name --- adapters/MicrosoftSQLServer.cfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100755 => 100644 adapters/MicrosoftSQLServer.cfc diff --git a/adapters/MicrosoftSQLServer.cfc b/adapters/MicrosoftSQLServer.cfc old mode 100755 new mode 100644 index 2dde6f1..2d1bf06 --- a/adapters/MicrosoftSQLServer.cfc +++ b/adapters/MicrosoftSQLServer.cfc @@ -211,7 +211,7 @@ if(arguments.type IS 'DATETIME' AND StructKeyExists(arguments.options,'limit') AND arguments.options.limit IS 'SMALL') { sql = 'SMALLDATETIME'; } else if(arguments.type IS 'DATETIME' AND StructKeyExists(arguments.options,'limit') AND isNumeric( arguments.options.limit )) { - sql = 'DATETIME2(#arguments.limit#)'; + sql = 'DATETIME2(#arguments.options.limit#)'; } else if(arguments.type IS 'MONEY' AND StructKeyExists(arguments.options,'limit') AND arguments.options.limit IS 'SMALL') { sql = 'SMALLMONEY'; } else if(arguments.type IS 'INTEGER' AND StructKeyExists(arguments.options,'limit') AND arguments.options.limit IS 'BIG') { From 260edf9bffc88252b2b24494dfd72514ded8f2ce Mon Sep 17 00:00:00 2001 From: Jordan Clark Date: Wed, 9 Oct 2013 19:53:36 -0700 Subject: [PATCH 17/17] Better DEFAULT support - Support empty string defaults (it doesn't have to be null) - Support SQL function defaults like GETDATE() --- adapters/MicrosoftSQLServer.cfc | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/adapters/MicrosoftSQLServer.cfc b/adapters/MicrosoftSQLServer.cfc index 2d1bf06..440630f 100644 --- a/adapters/MicrosoftSQLServer.cfc +++ b/adapters/MicrosoftSQLServer.cfc @@ -228,6 +228,33 @@ + + + + + + if(StructKeyExists(arguments.options,'type') && arguments.options.type != 'primaryKey') { + if(StructKeyExists(arguments.options,'default') && optionsIncludeDefault(argumentCollection=arguments.options)) { + if(arguments.options.default eq "NULL" || (arguments.options.default eq "" && ListFindNoCase("boolean,date,datetime,time,timestamp,decimal,float,integer",arguments.options.type))) { + arguments.sql = arguments.sql & " DEFAULT NULL"; + } else if( find( "(", arguments.options.default ) AND find( ")", arguments.options.default ) ) { // SQL Functions + arguments.sql = arguments.sql & " DEFAULT #arguments.options.default#"; + } else if(arguments.options.type == 'boolean') { + arguments.sql = arguments.sql & " DEFAULT #IIf(arguments.options.default,1,0)#"; + } else if(arguments.options.type == 'string' && arguments.options.default eq "") { + arguments.sql = arguments.sql & " DEFAULT ''"; + } else { + arguments.sql = arguments.sql & " DEFAULT #quote(value=arguments.options.default,options=arguments.options)#"; + } + } + if(StructKeyExists(arguments.options,'null') && !arguments.options.null) { + arguments.sql = arguments.sql & " NOT NULL"; + } + } + + + +