Support for Enum type in MySQL adapter. Requires patch to mainline JDB.

(See pull request: https://github.com/1602/jugglingdb/pull/296.)

After this there are several ways to use Enum with the adapter as shown in datatypes.test.js.
This commit is contained in:
dgsan 2013-06-17 14:25:57 -07:00
parent c6b4a70fc4
commit c1616fd998
3 changed files with 189 additions and 0 deletions

52
lib/enumFactory.js Normal file
View File

@ -0,0 +1,52 @@
function Enum() {
if(arguments.length > 0){
var dxList = [];
dxList.push(''); // Want empty value to be at index 0 to match MySQL Enum values and MySQL non-strict behavior.
for(var arg in arguments){
arg = String(arguments[arg]);
Object.defineProperty(this, arg.toUpperCase(), {configurable: false, enumerable: true, value: arg, writable: false});
dxList.push(arg);
}
Object.defineProperty(this, '_values', {configurable: false, enumerable: false, value: dxList, writable: false});
Object.defineProperty(this, '_string', {configurable: false, enumerable: false, value: stringified(this), writable: false});
Object.freeze(this);
return this;
} else {
throw "No arguments - can't create Enum.";
}
};
Object.defineProperty(Enum.prototype, 'name', {configurable: false, enumerable: false, value: 'Enum', writable: false});
var EnumFactory = (function() {
function FakeEnumConstructor(args) {
return Enum.apply(this, args);
}
FakeEnumConstructor.prototype = Enum.prototype;
return function() {
var returnObject = new FakeEnumConstructor(arguments);
returnObject.constructor = Enum.constructor;
return returnObject;
}
})();
function stringified(anEnum) {
var s = [];
for(var i in anEnum._values){
if(anEnum._values[i] != ''){
s.push("'" + anEnum._values[i] + "'");
}
}
return s.join(',');
}
exports.EnumFactory = EnumFactory;
exports.Enum = Enum;

View File

@ -3,6 +3,8 @@
*/
var mysql = require('mysql');
var jdb = require('jugglingdb');
var Enums = require('./enumFactory');
exports.initialize = function initializeSchema(schema, callback) {
if (!mysql) return;
@ -58,6 +60,12 @@ exports.initialize = function initializeSchema(schema, callback) {
// MySQL specific column types
schema.constructor.registerType(function Point() {});
schema.EnumFactory = Enums.EnumFactory; // factory for Enums
schema.Enum = Enums.Enum; // constructor for Enums
schema.constructor.registerType(Enums.Enum);
};
/**
@ -644,6 +652,10 @@ function datatype(p) {
case 'Point':
dt = 'POINT';
break;
case 'Enum':
dt = 'ENUM(' + p.type._string + ')';
dt = stringOptions(p, dt); // Enum columns can have charset/collation.
break;
}
return dt;
}

125
test/datatypes.test.js Normal file
View File

@ -0,0 +1,125 @@
var should = require('./init.js');
var assert = require('assert');
var Schema = require('jugglingdb').Schema;
var db, settings, adapter, EnumModel, ANIMAL_ENUM;
describe('MySQL specific datatypes', function() {
before(setup);
it('should run migration', function(done) {
db.automigrate(function(){
done();
});
});
it('should create a model instance with Enums', function(done) {
var em = EnumModel.create({animal: ANIMAL_ENUM.CAT, condition: 'sleepy', mood: 'happy'}, function(err, obj) {
assert.ok(!err);
assert.equal(obj.condition, 'sleepy');
EnumModel.findOne({where: {animal: ANIMAL_ENUM.CAT}}, function(err, found){
assert.ok(!err);
assert.equal(found.mood, 'happy');
assert.equal(found.animal, ANIMAL_ENUM.CAT);
done();
});
});
});
it('should fail spectacularly with invalid enum values', function(done) {
var em = EnumModel.create({animal: 'horse', condition: 'sleepy', mood: 'happy'}, function(err, obj) {
assert.ok(!err);
EnumModel.find(obj.id, function(err, found){
assert.ok(!err);
assert.equal(found.animal, ''); // MySQL fun.
assert.equal(found.animal, 0);
done();
});
});
});
it('should disconnect when done', function(done) {
db.disconnect();
done()
});
});
function setup(done) {
require('./init.js');
db = getSchema();
ANIMAL_ENUM = db.EnumFactory('dog', 'cat', 'mouse');
EnumModel = db.define('EnumModel', {
animal: { type: ANIMAL_ENUM, null: false },
condition: { type: db.EnumFactory('hungry', 'sleepy', 'thirsty') },
mood: { type: new db.Enum('angry', 'happy', 'sad') }
});
blankDatabase(db, done);
}
var query = function (sql, cb) {
db.adapter.query(sql, cb);
};
var blankDatabase = function (db, cb) {
var dbn = db.settings.database;
var cs = db.settings.charset;
var co = db.settings.collation;
query('DROP DATABASE IF EXISTS ' + dbn, function(err) {
var q = 'CREATE DATABASE ' + dbn;
if(cs){
q += ' CHARACTER SET ' + cs;
}
if(co){
q += ' COLLATE ' + co;
}
query(q, function(err) {
query('USE '+ dbn, cb);
});
});
};
getFields = function (model, cb) {
query('SHOW FIELDS FROM ' + model, function(err, res) {
if (err) {
cb(err);
} else {
var fields = {};
res.forEach(function(field){
fields[field.Field] = field;
});
cb(err, fields);
}
});
}
getIndexes = function (model, cb) {
query('SHOW INDEXES FROM ' + model, function(err, res) {
if (err) {
console.log(err);
cb(err);
} else {
var indexes = {};
// Note: this will only show the first key of compound keys
res.forEach(function(index) {
if (parseInt(index.Seq_in_index, 10) == 1) {
indexes[index.Key_name] = index
}
});
cb(err, indexes);
}
});
};