1 var Type = require("./index").Type,
  2         comb = require("comb");
  3 
  4 var stringDefaults = {
  5     allowNull : true,
  6     primaryKey : false,
  7     foreignKey : false,
  8     "default" : null,
  9     unique : false,
 10     description : ""
 11 };
 12 
 13 var getStringType = function(cmpFun) {
 14     return function(val) {
 15         if (!val) {
 16             val = null;
 17         } else if (typeof val != "string") {
 18             val = "" + val;
 19         }
 20         cmpFun && cmpFun(val);
 21         return val;
 22     };
 23 };
 24 
 25 var checkStringType = function(type, cmpFun) {
 26     return function(val) {
 27         if (typeof val != "string") throw new Error(type + " requires a string type.");
 28         cmpFun && cmpFun(val);
 29     };
 30 };
 31 
 32 //String Types
 33 /**
 34  *
 35  *
 36  * Mysql CHAR datatype
 37  *
 38  * @function
 39  * @param {Object} options options for the CHAR data type.
 40  * @param {Number} [options.length=255] the length of the field
 41  * @param {Boolean} [options.allowNull=true] should the field allow null
 42  * @param {Boolean} [options.default = null] default value of the field
 43  * @param {Boolean} [options.description = ""] description fo the field.
 44  *
 45  * @return {Type} A Type representing a CHAR column.
 46  *
 47  * @name CHAR
 48  * @memberOf moose.adapters.mysql.types
 49  *
 50  */
 51 exports.CHAR = function(options) {
 52     var ops = comb.merge({}, stringDefaults, {length : 255, type : "CHAR"}, options || {});
 53     if (ops.length > 4294967295) {
 54         throw new Error("Max char type length is 255");
 55     }
 56     var cmpFun = function(val) {
 57         if (ops.length == undefined && val.length > 255) throw new Error("value not of length " + (ops.length || 255));
 58         else if (val && val.length != ops.length) throw new Error("value not of length " + (ops.length || 255));
 59     };
 60     ops.setSql = getStringType(cmpFun);
 61     ops.checkType = checkStringType(ops.type, cmpFun);
 62     return new Type(ops);
 63 };
 64 
 65 /**
 66  *
 67  *
 68  * String alias for {@link varchar} datatype.
 69  *
 70  * @function
 71  * @param {Object} options options for the STRING data type.
 72  * @param {Number} [options.length=255] the length of the field
 73  * @param {Boolean} [options.allowNull=true] should the field allow null
 74  * @param {Boolean} [options.default = null] default value of the field
 75  * @param {Boolean} [options.description = ""] description fo the field.
 76  *
 77  * @return {Type} A Type representing a VARCHAR column.
 78  *
 79  * @name STRING
 80  * @memberOf moose.adapters.mysql.types
 81  *
 82  */
 83 exports.STRING = (exports.VARCHAR = function(options) {
 84     var ops = comb.merge({}, stringDefaults, {length : 255, type : "VARCHAR"}, options || {});
 85     if (ops.length > 4294967295) {
 86         throw new Error("Max char type length is 255 please use text");
 87     }
 88     var cmpFun = function(val) {
 89         if ((val.length > ops.length) || val.length > 255)
 90             throw new Error("value greater than valid varchar length of " + (ops.length || 255));
 91     };
 92     ops.setSql = getStringType(cmpFun);
 93     ops.checkType = checkStringType(ops.type, cmpFun);
 94     return new Type(ops);
 95 });
 96 
 97 /**
 98  *
 99  * Mysql TINYTEXT datatype
100  *
101  * @function
102  * @param {Object} options options for the TINYTEXT data type.
103  * @param {Number} [options.length] the length of the field
104  * @param {Boolean} [options.allowNull=true] should the field allow null
105  * @param {Boolean} [options.default = null] default value of the field
106  * @param {Boolean} [options.description = ""] description fo the field.
107  *
108  * @return {Type} A Type representing a TINYTEXT column.
109  *
110  * @name TINYTEXT
111  * @memberOf moose.adapters.mysql.types
112  *
113  */
114 exports.TINYTEXT = function(options) {
115     var ops = comb.merge({}, stringDefaults, {length : null, type : "TINYTEXT"}, options || {});
116     var cmpFun = function(val) {
117         if (val.length > 255) throw new Error("value greater than valid tinytext length of 255");
118     };
119     ops.setSql = getStringType(cmpFun);
120     ops.checkType = checkStringType(ops.type, cmpFun);
121     return new Type(ops);
122 };
123 
124 /**
125  *
126  *
127  * Mysql MEDIUMTEXT datatype
128  *
129  * @function
130  * @param {Object} options options for the MEDIUMTEXT data type.
131  * @param {Number} [options.length] the length of the field
132  * @param {Boolean} [options.allowNull=true] should the field allow null
133  * @param {Boolean} [options.default = null] default value of the field
134  * @param {Boolean} [options.description = ""] description fo the field.
135  *
136  * @return {Type} A Type representing a MEDIUMTEXT column.
137  *
138  * @name MEDIUMTEXT
139  * @memberOf moose.adapters.mysql.types
140  *
141  */
142 exports.MEDIUMTEXT = function(options) {
143     var ops = comb.merge({}, stringDefaults, {length : null, type : "MEDIUMTEXT"}, options || {});
144     var cmpFun = function(val) {
145         if (val.length > 16777215) throw new Error("value greater than valid tinytext length of 16777215");
146     };
147     ops.setSql = getStringType(cmpFun);
148     ops.checkType = checkStringType(ops.type, cmpFun);
149     return new Type(ops);
150 };
151 
152 /**
153  *
154  *
155  * Mysql LONGTEXT datatype
156  *
157  * @function
158  * @param {Object} options options for the LONGTEXT data type.
159  * @param {Number} [options.length] the length of the field
160  * @param {Boolean} [options.allowNull=true] should the field allow null
161  * @param {Boolean} [options.default = null] default value of the field
162  * @param {Boolean} [options.description = ""] description fo the field.
163  *
164  * @return {Type} A Type representing a LONGTEXT column.
165  *
166  * @name LONGTEXT
167  * @memberOf moose.adapters.mysql.types
168  *
169  */
170 exports.LONGTEXT = function(options) {
171     var ops = comb.merge({}, stringDefaults, {length : null, type : "LONGTEXT"}, options || {});
172     var cmpFun = function(val) {
173         if (val.length > 4294967295) throw new Error("value greater than valid tinytext length of 4294967295");
174     };
175     ops.setSql = getStringType(cmpFun);
176     ops.checkType = checkStringType(ops.type, cmpFun);
177     return new Type(ops);
178 };
179 
180 /**
181  *
182  *
183  * Mysql TEXT datatype
184  *
185  * @function
186  * @param {Object} options options for the TEXT data type.
187  * @param {Number} [options.length] the length of the field
188  * @param {Boolean} [options.allowNull=true] should the field allow null
189  * @param {Boolean} [options.default = null] default value of the field
190  * @param {Boolean} [options.description = ""] description fo the field.
191  *
192  * @return {Type} A Type representing a TEXT column.
193  *
194  * @name TEXT
195  * @memberOf moose.adapters.mysql.types
196  *
197  */
198 exports.TEXT = function(options) {
199     var ops = comb.merge({}, stringDefaults, {length : 4294967295, type : "TEXT"}, options || {});
200     var cmpFun = function(val) {
201         if (val.length > 65535) throw new Error("value greater than valid tinytext length of 65535");
202     };
203     ops.setSql = getStringType(cmpFun);
204     ops.checkType = checkStringType(ops.type, cmpFun);
205     return new Type(ops);
206 };
207 
208 
209 var checkEnumType = function(enumTypes, type) {
210     var enums = comb.merge([], enumTypes);
211     return function(val) {
212         if (typeof val != "string" || enums.indexOf(val) == -1) {
213             throw new Error(type + " value must be a string and contained in the enum set");
214         }
215     };
216 };
217 
218 var checkSetType = function(enumTypes, type) {
219     var check = checkEnumType(enumTypes, type);
220     return function(val) {
221         if (typeof val == "string") {
222             return check(val);
223         }
224         val.forEach(function(v) {
225             return check(v);
226         });
227     };
228 };
229 
230 
231 var getSetType = function(cmpFunc) {
232     return function(val) {
233         if (typeof val == "string") {
234             val = val.split(",");
235         }
236         cmpFunc && cmpFunc(val);
237         return val;
238     };
239 };
240 
241 /**
242  *
243  *
244  * Mysql ENUM datatype
245  *
246  * @function
247  * @param {Object} options options for the TINYTEXT data type.
248  * @param {Array} options.enums the characters allowed for this ENUM
249  * @param {Number} [options.length] the length of the field
250  * @param {Boolean} [options.allowNull=true] should the field allow null
251  * @param {Boolean} [options.default = null] default value of the field
252  * @param {Boolean} [options.description = ""] description fo the field.
253  *
254  * @return {Type} A Type representing a ENUM column.
255  *
256  * @name ENUM
257  * @memberOf moose.adapters.mysql.types
258  *
259  */
260 exports.ENUM = function(options) {
261     var ops = comb.merge({}, stringDefaults, {type : "ENUM", enums : []}, options || {});
262     if (ops.enums && ops.enums.length > 65535) {
263         throw new Error("Max number of enum values is 65535");
264     }
265     ops.setSql = getStringType(checkEnumType(ops.enums, ops.type));
266     ops.checkType = checkEnumType(ops.enums, ops.type);
267     return new Type(ops);
268 };
269 
270 /**
271  *
272  *
273  * Mysql SET datatype
274  *
275  * @function
276  * @param {Object} options options for the SET data type.
277  * @param {Array} options.enums the characters  allowed in this SET
278  * @param {Number} [options.length] the length of the field
279  * @param {Boolean} [options.allowNull=true] should the field allow null
280  * @param {Boolean} [options.default = null] default value of the field
281  * @param {Boolean} [options.description = ""] description fo the field.
282  *
283  * @return {Type} A Type representing a SET column.
284  *
285  * @name SET
286  * @memberOf moose.adapters.mysql.types
287  *
288  */
289 exports.SET = function(options) {
290     var ops = comb.merge({}, stringDefaults, {type : "SET", enums : []}, options || {});
291     if (ops.enums && ops.enums.length > 64) {
292         throw new Error("Max number of enum values is 64");
293     }
294     ops.setSql = getSetType(checkSetType(ops.enums, ops.type));
295     ops.checkType = checkSetType(ops.enums, ops.type);
296     return new Type(ops);
297 };
298