1 var comb = require("comb"),
  2         Client = require("mysql").Client;
  3 
  4 var toSqlDate = function(date, type) {
  5     var pad = comb.string.pad, ret, format = comb.date.format;
  6     switch (type) {
  7         case "DATE" :
  8             ret = format(date, "yyyy-MM-dd");
  9             break;
 10         case "DATETIME" :
 11         case "TIMESTAMP" :
 12             ret = format(date, "yyyy-MM-dd h:m:s");
 13             break;
 14         case "TIME" :
 15             ret = format(date, "h:m:s");
 16 
 17             break;
 18         case "YEAR" :
 19             ret = format(date, "yyyy");
 20             break;
 21     }
 22     return ret;
 23 };
 24 
 25 var genStringColumnDef = function(ops) {
 26     var numberTypes = ["TINYINT", "SMALLINT", "MEDIUMINT", "INT", "BIGINT", "FLOAT", "DOUBLE", "DECIMAL"];
 27     var colDef = "";
 28     if (ops.type) {
 29         colDef += ops.type.toUpperCase();
 30     } else {
 31         throw new Error("A type is required in a column definition");
 32     }
 33     if ((ops.type != "ENUM" && ops.type != "SET") && (ops.length != undefined || ops.size != undefined)) {
 34         colDef += "(" + (numberTypes.indexOf(ops.type) < 0 ? ops.length : ops.size);
 35         if (["FLOAT", "DOUBLE", "DECIMAL"].indexOf(ops.type) >= 0 && ops.digits) {
 36             colDef += "," + ops.digits;
 37         }
 38         colDef += ")";
 39     } else if (ops.type == "ENUM" || ops.type == "SET") {
 40         if (!ops.enums || !(ops.enums instanceof Array)) {
 41             throw new Error("and array of enum values required when using an enum type");
 42         } else {
 43             colDef += "(" + new Client().format(ops.enums.map(
 44                     function() {
 45                         return "?";
 46                     }).join(","), ops.enums.slice()) + ")";
 47         }
 48     }
 49     if (typeof ops.unsigned == "boolean" && numberTypes.indexOf(ops.type) >= 0) {
 50         colDef += ops.unsigned ? " UNSIGNED" : " SIGNED";
 51     }
 52     if (typeof ops.allowNull == "boolean") {
 53         colDef += ops.allowNull ? " NULL" : " NOT NULL";
 54     }
 55     if (ops.autoIncrement) {
 56         colDef += " AUTO_INCREMENT";
 57     }
 58     if (ops["default"] != undefined) {
 59         colDef += new Client().format(" DEFAULT ?", [ops["default"]]);
 60     }
 61     if (ops.unique) {
 62         colDef += " UNIQUE";
 63     }
 64     return colDef;
 65 };
 66 /* { Field: 'id',
 67  Type: 'int(11)',
 68  Null: 'NO',
 69  Key: 'PRI',
 70  Default: null,
 71  Extra: 'auto_increment' }*/
 72 var fromColumnDef = function(o) {
 73     var numberTypes = ["TINYINT", "SMALLINT", "MEDIUMINT", "INT", "BIGINT", "FLOAT", "DOUBLE", "DECIMAL"];
 74     var params = {};
 75     var colDef = "";
 76 
 77     var type = o.Type;
 78     var parts = type.split(/\(|,|\)/);
 79     if (parts.length > 1) {
 80         //remove the blank value at the end
 81         var i;
 82         if ((i = parts.indexOf("")) > 1) {
 83             parts.splice(i, 1);
 84         }
 85         //then we know it has a size, length and or digits
 86         type = parts.shift().toUpperCase();
 87         if (numberTypes.indexOf(type) >= 0) {
 88             params.size = parseInt(parts.shift());
 89             var digits = parts.shift();
 90             if (digits) {
 91                 if (["FLOAT", "DOUBLE", "DECIMAL"].indexOf(type) >= 0 && !isNaN(parseInt(digits))) {
 92                     params.digits = parseInt(digits);
 93                     digits = parts.shift();
 94                     //grab signed prop
 95                     if (digits && (digits === "signed" || digits === "unsigned")) {
 96                         params.unsigned = (digits == "unsigned");
 97                     }
 98                 } else if (digits === " signed" || digits === " unsigned") {
 99                     params.unsigned = (digits == " unsigned");
100                 }
101             }
102         } else {
103             if (parts.length && type == "ENUM" || type == "SET") {
104                 //assign the enums
105                 parts = parts.map(function(p) {
106                     return p.replace(/\\|'/g, "");
107                 });
108                 params.enums = parts;
109             } else if (parts.length) {
110                 params.length = parseInt(parts[0]);
111             }
112         }
113     } else {
114         type = type.toUpperCase();
115     }
116     if (o.Null) {
117         params.allowNull = o.Null === "YES";
118     }
119     if (o.Key) {
120         if (o.Key == "PRI") {
121             params.primaryKey = true;
122         }
123     }
124     if (o.Extra) {
125         var extras = o.Extra.split(" ");
126         params.autoIncrement = extras.indexOf("auto_increment") >= 0;
127 
128     }
129     if (o["Default"]) {
130         params["default"] = o["Default"];
131     }
132     return exports.types[type](params);
133 };
134 
135 /**
136  * @class
137  * Represents a mysql datatype. This Class should not be instantiated directly!
138  *
139  *
140  * @property {String} sql the column definition of this Type.
141  *
142  * @name Type
143  */
144 exports.Type = comb.define(null, {
145     instance : {
146         /**@lends Type.prototype*/
147 
148         constructor : function(options) {
149             this.__options = options;
150         },
151 
152         /**
153          * Set a property on this Type, such as isNull, unique, default etc...
154          *
155          * @param {String} name the name of the property.
156          * @param {*} value the value to set it to.
157          */
158         set : function(name, value) {
159             this.__options[name] = value;
160         },
161 
162 
163         /**
164          * Is this Type a primary key.
165          *
166          * @return {Boolean} true if this Type is a primary key.
167          */
168         isPrimaryKey : function() {
169             if (this.__options.primaryKey) {
170                 return true;
171             } else {
172                 false;
173             }
174         },
175 
176         /**
177          * Convert an SQL value to the javascript equivalent. This method will do a type check after the conversionn.
178          *
179          * @param {String} val the sql string to convert.
180          *
181          * @return {*} the javascript value.
182          */
183         fromSql : function(val) {
184             var ret = (val == "null" || val == "NULL") ? null : val;
185             if (ret != null) {
186                 ret = this.__options.setSql(ret);
187             }
188             return ret;
189         },
190 
191         /**
192          * Converts a javacript value to the corresponding sql equivalent.
193          * This function does a type check on the value before conversion, if it is not the right type an error is thrown.
194          * @param {*} val the javacript value to convert
195          *
196          * @return {String} the sql value.
197          */
198         toSql : function(val) {
199             this.check(val);
200             if (val instanceof Date) {
201                 val = toSqlDate(val, this.__options.type);
202             } else if (val instanceof Array) {
203                 val = val.join(",");
204             } else if (val == null || val == undefined) {
205                 val = null;
206             }
207             return val;
208         },
209 
210         /**
211          * Checks a value against this Type column definition.
212          *
213          * @param {*} value the value to check.
214          *
215          * @return {Boolean} true if the value is valid.
216          */
217         check : function(value) {
218             if ((value == null && !this.__options.allowNull) && !(this.primaryKey && this.__options.autoIncrement)) {
219                 throw new Error("value is not allowed to be null");
220             } else if (value != null) {
221                 this.__options.checkType(value);
222             }
223             return true;
224         },
225 
226         getters : {
227             sql : function() {
228                 return genStringColumnDef(this.__options);
229             }
230         }
231 
232     }
233 });
234 
235 
236 /**
237  * @function
238  * Creates foreign key syntax
239  *
240  * @example
241  *
242  * //FOREIGN KEY (myColumn) REFERENCES otherTable (otherTableColumn)
243  * moose.adapters.mysql.foreignKey("myColumn", {otherTable : "otherTableColumn"});
244  *
245  * //FOREIGN KEY (myColumn, myColumn2)
246  * //     REFERENCES otherTable (otherTableColumn, otherTableColumn2)
247  * moose.adapters.mysql.foreignKey([myColumn, myColumn2], {
248  *              otherTable : ["otherTableColumn", "otherTableColumn2"]
249  * });
250  *
251  * //FOREIGN KEY (myColumn) REFERENCES otherTable (otherTableColumn),
252  * //FOREIGN KEY (myColumn2) REFERENCES otherTable2 (otherTableColumn2)
253  * moose.adapters.mysql.foreignKey({
254  *              myColumn : {otherTable : "otherTableColumn"},
255  *              myColumn2 : {otherTable2 : "otherTableColumn2"}
256  * });
257  *
258  * @param {String|Array|Object} name
259  * <ul>
260  *     <li>If a String is provided then it is assumed to be the name of the column</li>
261  *     <li>If an array is provided then it assumed to be an array of columns that reference the columns specified in the foreign table.</li>
262  *     <li>If an object is specified then its treated as multiple foreign keys against multiple tables.</li>
263  * </ul>
264  * @param {Object} options object containg the foreignTable as the key and the value should be either a string or array,
265  *                 depending on the name parameter, see the example.
266  *
267  * @return {String} the sql
268  *
269  * @name foreignKey
270  * @memberOf moose.adapters.mysql
271  */
272 
273 exports.foreignKey = function(name, options) {
274     var sql, i;
275     if (name instanceof Array) {
276         if (typeof options != "object") throw new Error("when calling foreign key options must be an object");
277         var fkName = createContraintName("fk", name);
278         sql = "CONSTRAINT " + fkName + " FOREIGN KEY (" + name.join(",") + ")";
279         var otherTable, columns = null;
280         for (i in options) {
281             otherTable = i;
282             columns = options[i];
283         }
284         if (columns.length == name.length) {
285             sql += " REFERENCES " + otherTable + " (" + columns.join(",") + ")";
286         } else {
287             throw new Error("parent table columns must be the same length as the table columns");
288         }
289     } else if (typeof name == "object") {
290         var fKeys = [];
291         for (i in name) {
292             fKeys.push(exports.foreignKey(i, name[i]));
293         }
294         sql = fKeys.join(",");
295     } else if (typeof name == "string") {
296         if (typeof options != "object") throw new Error("when calling foreign key options must be an object");
297         sql = "FOREIGN KEY (" + name + ")",count = 0;
298         for (i in options) {
299             if (count != 0) throw new Error("when calling foreing key with a string for the column name, you options must be a one deep object");
300             if (typeof options[i] == "string") {
301                 sql += " REFERENCES " + i + " (" + options[i] + ")";
302             } else {
303                 throw new Error("parents column name must be a string when calling foreign key with a string for column name");
304             }
305         }
306     } else {
307         throw new Error("When calling foreign key you must pass an array, object, or string as columnName");
308     }
309     return sql;
310 };
311 
312 /**
313  * @function
314  * Creates alter table foreign key syntax
315  *
316  * @example
317  *
318  * //ADD FOREIGN KEY (myColumn) REFERENCES otherTable (otherTableColumn)
319  * moose.adapters.mysql.addForeignKey("myColumn", {otherTable : "otherTableColumn"}
320  *
321  * //ADD CONSTRAINT fk_myColumnMyColumn2... FOREIGN KEY (myColumn, myColumn2)
322  * //             REFERENCES otherTable (otherTableColumn, otherTableColumn2)
323  * moose.adapters.mysql.addForeignKey([myColumn, myColumn2], {
324  *                  otherTable : ["otherTableColumn", "otherTableColumn2"]
325  * });
326  *
327  * //ADD FOREIGN KEY (myColumn) REFERENCES otherTable (otherTableColumn),
328  * //ADD FOREIGN KEY (myColumn2) REFERENCES otherTable2 (otherTableColumn2)
329  * moose.adapters.mysql.addForeignKey({
330  *                  myColumn : {otherTable : "otherTableColumn"},
331  *                  myColumn2 : {otherTable2 : "otherTableColumn2"}
332  *});
333  *
334  *
335  * @param {String|Array|Object} name
336  * <ul>
337  *     <li>If a String is provided then it is assumed to be the name of the column</li>
338  *     <li>If an array is provided then it assumed to be an array of columns that reference the columns specified in the foreign table.</li>
339  *     <li>If an object is specified then its treated as multiple foreign keys against multiple tables.</li>
340  * </ul>
341  * @param {Object} options object containg the foreignTable as the key and the value should be either a string or array,
342  *                 depending on the name parameter, see the example.
343  * @return {String} the sql
344  *
345  * @name addForeignKey
346  * @memberOf moose.adapters.mysql
347  **/
348 
349 exports.addForeignKey = function(name, options) {
350     var sql, i;
351     if (name instanceof Array) {
352         if (typeof options != "object") throw new Error("when calling foreign key options must be an object");
353         var fkName = createContraintName("fk", name);
354         sql = "ADD CONSTRAINT " + fkName + " FOREIGN KEY (" + name.join(",") + ")";
355         var otherTable, columns = null;
356         for (i in options) {
357             otherTable = i;
358             columns = options[i];
359         }
360         if (columns.length == name.length) {
361             sql += " REFERENCES " + otherTable + " (" + columns.join(",") + ")";
362         } else {
363             throw new Error("parent table columns must be the same length as the table columns");
364         }
365     } else if (typeof name == "object") {
366         var fKeys = [];
367         for (i in name) {
368             fKeys.push(exports.addForeignKey(i, name[i]));
369         }
370         sql = fKeys.join(",");
371     } else if (typeof name == "string") {
372         if (typeof options != "object") throw new Error("when calling foreign key options must be an object");
373         sql = "ADD FOREIGN KEY (" + name + ")",count = 0;
374         for (i in options) {
375             if (count != 0) throw new Error("when calling foreing key with a string for the column name, you options must be a one deep object");
376             if (typeof options[i] == "string") {
377                 sql += " REFERENCES " + i + " (" + options[i] + ")";
378             } else {
379                 throw new Error("parents column name must be a string when calling foreign key with a string for column name");
380             }
381         }
382     } else {
383         throw new Error("When calling addForeign key you must pass an array, object, or string as columnName");
384     }
385     return sql;
386 };
387 
388 
389 /**
390  * @function
391  * Creates drop foreign key syntax
392  *
393  * @example
394  *
395  * //DROP FOREIGN KEY myColumn
396  * moose.adapters.mysql.dropForeignKey("myColumn", {otherTable : "otherTableColumn"}
397  *
398  * //DROP FOREIGN KEY fk_myColumnMyColumn2
399  * moose.adapters.mysql.foreignKey([myColumn, myColumn2], {
400  *              otherTable : ["otherTableColumn", "otherTableColumn2"]
401  * });
402  *
403  * //DROP FOREIGN KEY myColumn,
404  * //DROP FOREIGN KEY myColumn2
405  * moose.adapters.mysql.foreignKey({
406  *              myColumn : {otherTable : "otherTableColumn"},
407  *              myColumn2 : {otherTable2 : "otherTableColumn2"}
408  * });
409  *
410  *
411  * @param {String|Array|Object} name
412  * <ul>
413  *     <li>If a String is provided then it is assumed to be the name of the column</li>
414  *     <li>If an array is provided then it assumed to be an array of columns that reference the columns specified in the foreign table.</li>
415  *     <li>If an object is specified then its treated as multiple foreign keys against multiple tables.</li>
416  * </ul>
417  * @param {Object} options object containg the foreignTable as the key and the value should be either a string or array,
418  *                 depending on the name parameter, see the example.
419  * @return {String} the sql
420  *
421  * @name dropForeignKey
422  * @memberOf moose.adapters.mysql
423  **/
424 exports.dropForeignKey = function(name, options) {
425     var sql;
426     if (name instanceof Array) {
427         if (typeof options != "object") throw new Error("when calling foreign key options must be an object");
428         var fkName = createContraintName("fk", name);
429         sql = "DROP FOREIGN KEY " + fkName;
430     } else if (typeof name == "object") {
431         var fKeys = [];
432         for (var i in name) {
433             fKeys.push(exports.dropForeignKey(i, name[i]));
434         }
435         sql = fKeys.join(",");
436     } else if (typeof name == "string") {
437         if (typeof options != "object") throw new Error("when calling foreign key options must be an object");
438         sql = "DROP FOREIGN KEY " + name;
439     } else {
440         throw new Error("When calling dropForeign key you must pass an array, object, or string as columnName");
441     }
442     return sql;
443 };
444 
445 var createContraintName = function(prefix, names, postFix) {
446     postFix = postFix || "",prefix = prefix || "";
447     var ret = names.map(
448             function(p, i) {
449                 if (i) {
450                     return p.charAt(0).toUpperCase() + p.substr(1);
451                 } else {
452                     return p;
453                 }
454             }).join("");
455     prefix && (ret = prefix + "_" + ret);
456     postFix && (ret += "_" + postFix);
457     return ret;
458 };
459 
460 
461 /**
462  * @function
463  * Creates primary key syntax
464  *
465  * @example
466  *
467  * //PRIMARY KEY (myColumn)
468  * moose.adapters.mysql.primaryKey("myColumn"}
469  *
470  * //PRIMARY KEY (myColumn, myColumn2, ...)
471  * moose.adapters.mysql.primaryKey([myColumn, myColumn2, ...]);
472  *
473  * @param {String|Array} name name or names of columns to create a primary key.
474  *
475  * @return {String} the sql
476  *
477  * @name primaryKey
478  * @memberOf moose.adapters.mysql
479  **/
480 exports.primaryKey = function(name) {
481     var sql;
482     if (name instanceof Array) {
483         var pkName = createContraintName("pk", name);
484         sql = "CONSTRAINT " + pkName + " PRIMARY KEY (" + name.join(",") + ")";
485     } else if (typeof name == "string") {
486         sql = "PRIMARY KEY (" + name + ")";
487     } else {
488         throw new Error("When calling primaryKey the key must be a string or array");
489     }
490     return sql;
491 };
492 
493 /**
494  * @function
495  * Creates add primary key syntax
496  *
497  * @example
498  *
499  * //ADD PRIMARY KEY (myColumn)
500  * moose.adapters.mysql.addPrimaryKey("myColumn"}
501  *
502  * //ADD CONSTRAINT pk_myColumnMyColumn2... PRIMARY KEY (myColumn, myColumn2, ...)
503  * moose.adapters.mysql.addPrimaryKey([myColumn, myColumn2, ...]);
504  *
505  * @param {String|Array} name name or names of columns to create a primary key.
506  *
507  * @return {String} the sql
508  *
509  * @name addPrimaryKey
510  * @memberOf moose.adapters.mysql
511  **/
512 exports.addPrimaryKey = function(name) {
513     var sql;
514     if (name instanceof Array) {
515         var pkName = createContraintName("pk", name);
516         sql = "ADD CONSTRAINT " + pkName + " PRIMARY KEY (" + name.join(",") + ")";
517     } else if (typeof name == "string") {
518         sql = "ADD PRIMARY KEY (" + name + ")";
519     } else {
520         throw new Error("When calling addPrimaryKey the key must be a string or array");
521     }
522     return sql;
523 };
524 
525 /**
526  * @function
527  * Creates drop primary key syntax
528  *
529  * @example
530  *  //DROP PRIMARY KEY
531  * dropPrimaryKey()
532  *
533  * @return {String} the sql
534  *
535  * @name dropPrimaryKey
536  * @memberOf moose.adapters.mysql
537  **/
538 exports.dropPrimaryKey = function(name) {
539     return "DROP PRIMARY KEY";
540 };
541 
542 /**
543  * @function
544  * Creates unique syntax
545  *
546  * @example
547  * //UNIQUE (myColumn)
548  * moose.adapters.mysql.unique("myColumn"}
549  *
550  * //CONSTRAINT uc_myColumnMyColumn2... UNIQUE (myColumn, myColumn2, ...)
551  * moose.adapters.mysql.unique([myColumn, myColumn2, ...]);
552  *
553  * @param {String|Array} name name or names of columns to create a unique constraint.
554  *
555  * @return {String} the sql
556  *
557  * @name unique
558  * @memberOf moose.adapters.mysql
559  **/
560 exports.unique = function(name) {
561     var sql;
562     if (name instanceof Array) {
563         var ucName = createContraintName("uc", name);
564         sql = "CONSTRAINT " + ucName + " UNIQUE (" + name.join(",") + ")";
565     } else if (typeof name == "string") {
566         sql = "UNIQUE (" + name + ")";
567     } else {
568         throw new Error("When calling unique the key must be a string or array");
569     }
570     return sql;
571 };
572 
573 /**
574  * @function
575  * Creates add unique syntax
576  *
577  * @example
578  *
579  * //ADD UNIQUE (myColumn)
580  * moose.adapters.mysql.addUnique("myColumn"}
581  *
582  * //ADD CONSTRAINT uc_myColumnMyColumn2... UNIQUE (myColumn, myColumn2, ...)
583  * moose.adapters.mysql.addUnique([myColumn, myColumn2, ...]);
584  *
585  * @param {String|Array} name name or names of columns to create a unique constraint.
586  *
587  * @return {String} the sql
588  *
589  * @name addUnique
590  * @memberOf moose.adapters.mysql
591  **/
592 exports.addUnique = function(name) {
593     var sql;
594     if (name instanceof Array) {
595         var ucName = createContraintName("uc", name);
596         sql = "ADD CONSTRAINT " + ucName + " UNIQUE (" + name.join(",") + ")";
597         + ")";
598     } else if (typeof name == "string") {
599         sql = "ADD UNIQUE (" + name + ")";
600     } else {
601         throw new Error("When calling addUnique the key must be a string or array");
602     }
603     return sql;
604 };
605 
606 /**
607  * @function
608  * Creates drop unique syntax
609  *
610  *
611  * @example
612  *
613  * //DROP INDEX myColumn
614  * moose.adapters.mysql.dropUnique("myColumn")
615  *
616  * //DROP INDEX uc_myColumnMyColumn2
617  * moose.adapters.mysql.dropUnique([myColumn, myColumn2, ...]);
618  *
619  * @param {String|Array} name name or names of columns to create a unique constraint.
620  *
621  * @return {String} the sql
622  *
623  * @name dropUnique
624  * @memberOf moose.adapters.mysql
625  **/
626 exports.dropUnique = function(name) {
627     var sql;
628     if (name instanceof Array) {
629         var ucName = createContraintName("uc", name);
630         sql = "DROP INDEX " + ucName;
631         + ")";
632     } else if (typeof name == "string") {
633         sql = "DROP INDEX " + name;
634     } else {
635         throw new Error("When calling dropUnique the key must be a string or array");
636     }
637     return sql;
638 };
639 
640 /**
641  * Create the column definition of a type
642  *
643  * @function
644  *
645  * @param {String} name the name of the column
646  * @param {Type} type the Type object of the column
647  *
648  * @return {String} the sql
649  *
650  * @name column
651  * @memberOf moose.adapters.mysql
652  */
653 exports.column = function(name, type) {
654     var sql = "";
655     if (!name) throw new Error("when calling alterColumn columnName is required.");
656     return name + " " + type.sql;
657 };
658 
659 /**
660  * Creates the alter column syntax.
661  *
662  * @function
663  *
664  * @param {String} name the name of the column
665  * @param {Object} options parameters representing how to transform the column
666  * @param {Type} [options.type] the Type object of the column.
667  * @param {String} [options.newName] the new name of the column.
668  * @param {Type} [options.original] the original type of the column
669  * @prams {Boolean} [options.allowNull] the change the column to allow null
670  * @param {*} [options.default] change the default value of the column.
671  *
672  * @return {String} the sql
673  *
674  * @name alterColumn
675  * @memberOf moose.adapters.mysql
676  */
677 exports.alterColumn = function(name, options) {
678     var sql = "";
679     if (!name) throw new Error("when calling alterColumn columnName is required.");
680     if (options.type) {
681         if (options.newName) {
682             sql += "CHANGE COLUMN " + name + " " + options.newName;
683         } else {
684             sql += "MODIFY COLUMN " + name;
685         }
686         //the type is being changed
687         sql += " " + options.type.sql;
688     } else {
689         var original = options.original;
690         if (original) {
691             if (options.newName) {
692                 sql += "CHANGE COLUMN " + name + " " + options.newName;
693             } else {
694                 sql += "MODIFY COLUMN " + name;
695             }
696             if (options.allowNull != undefined) {
697                 original.set("allowNull", options.allowNull);
698             }
699             if (options["default"] != undefined) {
700                 original.set("default", options["default"]);
701             }
702             sql += " " + original.sql;
703         }
704 
705     }
706     return sql;
707 };
708 
709 /**
710  * Create add column syntax.
711  *
712  * @function
713  *
714  * @param {String} name name of the column
715  * @param {Type} type the Type object representing the column
716  *
717  * @return {String} the sql
718  *
719  * @name addColumn
720  * @memberOf moose.adapters.mysql
721  *
722  */
723 exports.addColumn = function(name, type) {
724     var sql = "";
725     if (!name) throw new Error("when calling alterColumn columnName is required.");
726     return "ADD COLUMN " + name + " " + type.sql;
727 };
728 
729 /**
730  * Create drop column syntax.
731  *
732  * @function
733  *
734  * @param {String} name name of the column being dropped.
735  *
736  *@return {String} the sql
737  *
738  * @name dropColumn
739  * @memberOf moose.adapters.mysql
740  */
741 exports.dropColumn = function(name) {
742     return "DROP COLUMN " + name;
743 };
744 
745 /**
746  * @name types
747  * @memberOf moose.adapters.mysql
748  * @namespace
749  */
750 exports.types = comb.merge({}, require("./string"), require("./number"), require("./boolean"), require("./date"));
751 exports.isValidType = function(o) {
752     return o instanceof exports.Type;
753 };
754 
755 
756 /**
757  * Creates a {@link Type} from a column defintion
758  *
759  * @function
760  * @param {Object} sql the sql type definition returned from a table query.
761  *
762  * @return {Type} The Type
763  *
764  * @name fromColDef
765  * @memberOf moose.adapters.mysql
766  */
767 exports.fromColDef = fromColumnDef;
768 
769