Skip to content
This repository

JugglingDB Support #153

Open
wants to merge 4 commits into from

2 participants

Cameron Bytheway Andreas Richter
Cameron Bytheway

I added support for the ORM framework JugglingDB which creates a multi-database compatibility layer. The api is very similar to mongoose making it easier to transition to. IMO this will add even more flexibility to calipso.

This PR isn't completely ready yet but I did want to create it to get some feedback and possibly help with testing.

I've ran the tests and they all pass on mongodb and the in-place memory adapter. The redis adapter does not work when assigning roles because it won't store an array which I'll hopefully fix in the juggling adapter. I haven't been able to test the rest of the adapters though it shouldn't be to hard to do.

Let me know what you think.

Andreas Richter
Collaborator

Could you rebase this? I am sorry but I merged a large commit of mine. I would like to quickly try this to see if it makes sense to merge or put it on another branch.

Cameron Bytheway

Just rebased it. I wasn't able to test it because I'm pretty busy with other projects currently. If I can do anything to help let me know and I should be able to work some time in.

Andreas Richter
Collaborator
Andreas Richter
Collaborator

Sorry, I did not get around to testing this. Are there other projects using jugglingdb yet? I actually have some other projects this might be interesting for as well.

Cameron Bytheway

Yeah railway.js uses it as its ORM.

Andreas Richter
Collaborator

This is still pending, sorry. I kind of got caught up in windows specific things and wanted support for google, twitter and facebook auth.

Andreas Richter
Collaborator

I am planning to do this next; getting windows support and everyauth took longer than expected. If you can rebase this it would be greatly appreciated, otherwise I am pretty sure I can figure it out.

Cameron Bytheway

No problem. I'll do that later today.

Andreas Richter
Collaborator

I created a branch "CamShaft-jugglingdb" with the merge. I am having some problems with it and some comments.
1. Somehow I can't login using it but it's also not throwing any errors. I'll need to debug but maybe you can check it out.
2. Would it be possible to assume {where:{...}} if you only get {...} so that existing findOne or find doesn't need to change? This is important because other modules would need to be rewritten even through almost 100% of them are just doing a plain where.

Andreas Richter
Collaborator

FYI the active branch in calipso is "master". The "devel" branch is a little behind currently.

Andreas Richter
Collaborator

I am having a problem at https://gist.github.com/4021763 on line 22.
Basically it seems that the Schema can't be used as a constructor but tries to create a new schema.
This tries to decode a value as a type. Any suggestions?

GOOD NEWS! This redis adapter version is deprecated, use redis2 instead. A lot of improvements, and new indexes incompatible with old (sorry about that): now we only store id and not ModelName:id in indexes. Also dates format in indexes changed to unix timestamp for better sorting and filtering performance
5 Nov 19:58:25 - info: Installing module content

welcome, message, default

I added a console.log(self.__data[attr]) at node_modules/jugglingdb/lib/abstract-class.js:82

SyntaxError: Unexpected token w
    at Object.parse (native)
    at AbstractClass._initProperties.def (/Users/andy/calipso/node_modules/jugglingdb/lib/abstract-class.js:82:46)
    at Array.forEach (native)
    at Function.Schema.define.NewClass.forEachProperty (/Users/andy/calipso/node_modules/jugglingdb/lib/schema.js:193:33)
    at ModelConstructor.AbstractClass._initProperties (/Users/andy/calipso/node_modules/jugglingdb/lib/abstract-class.js:74:10)
    at ModelConstructor.AbstractClass (/Users/andy/calipso/node_modules/jugglingdb/lib/abstract-class.js:30:10)
    at new ModelConstructor (/Users/andy/calipso/node_modules/jugglingdb/lib/schema.js:153:23)
    at Object.install (/Users/andy/calipso/modules/core/content/content.js:989:12)
    at /Users/andy/calipso/modules/core/admin/admin.js:540:40
    at Array.forEach (native)
5 Nov 19:58:25 - error: Module 'content' was unable to be installed... Reason: Object welcome, message, default has no method 'forEach'
Andreas Richter
Collaborator

FYI same thing happens with memory database type. Just so you don't specifically check redis:

5 Nov 20:30:23 - info: Installing module content
SyntaxError: Unexpected token w
    at Object.parse (native)
    at AbstractClass._initProperties.def (/Users/andy/calipso/node_modules/jugglingdb/lib/abstract-class.js:81:46)
    at Array.forEach (native)
    at Function.Schema.define.NewClass.forEachProperty (/Users/andy/calipso/node_modules/jugglingdb/lib/schema.js:193:33)
    at ModelConstructor.AbstractClass._initProperties (/Users/andy/calipso/node_modules/jugglingdb/lib/abstract-class.js:74:10)
    at ModelConstructor.AbstractClass (/Users/andy/calipso/node_modules/jugglingdb/lib/abstract-class.js:30:10)
    at new ModelConstructor (/Users/andy/calipso/node_modules/jugglingdb/lib/schema.js:153:23)
    at Object.install (/Users/andy/calipso/modules/core/content/content.js:989:12)
    at /Users/andy/calipso/modules/core/admin/admin.js:540:40
    at Array.forEach (native)
5 Nov 20:30:23 - error: Module 'content' was unable to be installed... Reason: Object welcome, message, default has no method 'forEach'
5 Nov 20:30:23 - info: Installing module contentTypes
Andreas Richter
Collaborator

Figured out this particular problem. The defaults for the initial contents records didn't have an Array as the initial value for the tags property. Your lib was trying to parse it as Json, I suppose mongoose tries to split a string by "," and uses that.

Andreas Richter
Collaborator

Having problems with strings. When I try to serialize the user object into the cookie it looks like this:

{"username":"andy","isAdmin":false,"id":1,"language":"en","roles":[{"0":"A","1":"d","2":"m","3":"i","4":"n","5":"i","6":"s","7":"t","8":"r","9":"a","10":"t","11":"o","12":"r","bold":"\u001b[1mAdministrator\u001b[22m","underline":"\u001b[4mAdministrator\u001b[24m","italic":"\u001b[3mAdministrator\u001b[23m","inverse":"\u001b[7mAdministrator\u001b[27m","grey":"\u001b[90mAdministrator\u001b[39m","black":"\u001b[30mAdministrator\u001b[39m","yellow":"\u001b[33mAdministrator\u001b[39m","red":"\u001b[31mAdministrator\u001b[39m","green":"\u001b[32mAdministrator\u001b[39m","blue":"\u001b[34mAdministrator\u001b[39m","white":"\u001b[37mAdministrator\u001b[39m","cyan":"\u001b[36mAdministrator\u001b[39m","magenta":"\u001b[35mAdministrator\u001b[39m","rainbow":"\u001b[31mA\u001b[39m\u001b[33md\u001b[39m\u001b[32mm\u001b[39m\u001b[34mi\u001b[39m\u001b[35mn\u001b[39m\u001b[31mi\u001b[39m\u001b[33ms\u001b[39m\u001b[32mt\u001b[39m\u001b[34mr\u001b[39m\u001b[35ma\u001b[39m\u001b[31mt\u001b[39m\u001b[33mo\u001b[39m\u001b[32mr\u001b[39m","zebra":"A\u001b[7md\u001b[27mm\u001b[7mi\u001b[27mn\u001b[7mi\u001b[27ms\u001b[7mt\u001b[27mr\u001b[7ma\u001b[27mt\u001b[7mo\u001b[27mr","zalgo":"A̸͕̖̲̲̝̙̱̝̯̯͖̱̰͍̍ͪ̇̅ͥ̑̄̾̈̇̌̌ͤ̽͋̑d̦͓͈̠̤͚̬͚̦̯̮͎̘͇̲̣̱̩̻̬̬͖̯̺̮̼̗̗͍̠͖͇̣͚̱͎͍̤̝̞̻̗͉͚̣̤̮͔͚̯̹̱͚̽ͫ͋ͬͨͧ͜m̷̗̺̲̰̙̩̯̟̹͔̙̼̭̫̰͙̜̻͍̮̮͚͍͚͍̙̬̦̻̖̻̹͕̦̊̉̎̔ͭ͊̈̈͊̍͋́ͦ͋̍ͅi̛̬͙̦̫̲̳̣͈͇̬̮̤̣̲̙͇̪̲̦̜̩͕̯̼̖̟̓ͧͩ̓n͉̲̯̯͇͔̄ͧ̌ͯͤ͊̂̎̇̅ͭ̈̓͗̽ͭ͞ͅi̬͖͎̯͚͓͕͈̬̮̜̠͓̩̻̲̙̲̠̳̻̥̥̞̳̩̜͚͚̪̯̬̪̤͙͙̲͔̪̝͖̓̿͌̓͂̅̃̈̎̀s̶̠͎̣̫̱̮̭̩̪̬͇̙̤̣͕̟̱̻͉̻̣̥̬̞̠̯͕̫ͤ́̉̌͋̾ͅt̸̟̪̱̬͎̟̟̳̹̯̲̝̦̼͎͎͙̑ͩ̏ͦͣͥͤ̄̓̎ͨ̏ͩ̇͆̀̔ͅȓ̡͍͎̼̭͎̠͓̪́̏̿͗͊ͥͮ̋ͫ̂̅͊á̫̯̰̼͕̤̻͎̝͔̖͓̲̠̜̔̾ͮͪ̽͊̈̄́̀̃̈͠ͅt̜̬̭̥̺̦̩̗̞̭̲͇̤͖̳̳̰̬̺̫͈̏́ͣ͋̋̋̽̓ͧ̓ͤ͡o̞̲̙͚̹̦͈̺̬̱̝̳̞͕͈̞̪̮̖̤̭͔̤̭̬̼̫̘̦̲̖̪̬̜͖̠̗̯͇̙͈̾̌̂͗̾̓ͬ̍ͣͨ̎ͩ̍̀̾͠ȓ̟̪͇̻͕̰̪̦̯̤͇ͭͤ̄́ͅ","stripColors":"Administrator","id":1}]}

Which seems to be due to the fact the "new String('something')" in node is not a string but an object of type String. I tried to find out on the node chat to see if this is recent but I doubt it.

Andreas Richter
Collaborator

I think there are problems with the List class. Adding an itemType property to the roles definition makes it work a tiny bit better but it's still broken. The redis2 adapter doesn't work unless indexes are defined and the redis adapter says it's deprecated. Boolean values are converted to strings of "true" and "false" and therefore "false" will show up as true. Do you have any suggestions on how to proceed? Or should we just wait?

Cameron Bytheway

ATM I don't have much time to look at it. I'm not using calipso anymore so it isn't a high priority for me.

That being said, if you feel like this is something that it's something you guys want, I can set aside some time to look at it.

Andreas Richter
Collaborator
Cameron Bytheway

I have seen that issue with it before and it probably should be fixed upstream. It's an issue with those drivers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.

Showing 30 changed files with 485 additions and 321 deletions. Show diff stats Hide diff stats

  1. 5  lib/calipso.js
  2. 6  lib/conf/default.json
  3. 4  lib/core/Form.js
  4. 2  lib/core/Lib.js
  5. 147  lib/core/SessionStorage.js
  6. 125  lib/core/Storage.js
  7. 3  lib/core/Table.js
  8. 2  lib/core/Utils.js
  9. 78  modules/core/admin/admin.js
  10. 26  modules/core/admin/templates/{install_mongo.html → install_db.html}
  11. 4  modules/core/admin/templates/install_user.html
  12. 2  modules/core/admin/templates/install_welcome.html
  13. 88  modules/core/content/content.js
  14. 2  modules/core/content/templates/listAdmin.html
  15. 21  modules/core/contentTypes/contentTypes.js
  16. 2  modules/core/contentTypes/templates/list.html
  17. 33  modules/core/contentVersions/contentVersions.js
  18. 10  modules/core/contentVersions/templates/list.html
  19. 4  modules/core/contentVersions/templates/show.html
  20. 14  modules/core/permissions/permissions.js
  21. 34  modules/core/scheduler/scheduler.js
  22. 26  modules/core/tagcloud/tagcloud.js
  23. 25  modules/core/taxonomy/taxonomy.js
  24. 2  modules/core/user/templates/role.list.html
  25. 52  modules/core/user/user.js
  26. 24  modules/core/user/user.roles.js
  27. 11  package.json
  28. 3  test/helpers/defaultConfig.json
  29. 45  test/{lib.core.storage.js-disabled → lib.core.storage.js}
  30. 6  themes/core/cleanslate/public/css/installation.css
5  lib/calipso.js
@@ -155,8 +155,8 @@ function initialiseCalipso(reloadConfig) {
155 155
   // Configure the logging
156 156
   calipso.logging.configureLogging();
157 157
 
158  
-  // Check / Connect Mongo
159  
-  calipso.storage.mongoConnect(calipso.config.get('database:uri'), false, function(err, connected) {
  158
+  // Check / Connect Database
  159
+  calipso.storage.connect(calipso.config.get('database:type'), calipso.config.get('database:configuration'), false, function(err, connected) {
160 160
 
161 161
     if (err) {
162 162
       console.log("There was an error connecting to the database: " + err.message);
@@ -175,6 +175,7 @@ function initialiseCalipso(reloadConfig) {
175 175
           // Initialise, callback via calipso.initCallback
176 176
           calipso.module.initModules();
177 177
 
  178
+          calipso.db.autoupdate();
178 179
         });
179 180
 
180 181
       });
6  lib/conf/default.json
@@ -2,7 +2,11 @@
2 2
   "version":"0.3.0",
3 3
   "installed":false,
4 4
   "database": {
5  
-    "uri":"mongodb://localhost/calipso"
  5
+    "type": "memory",
  6
+    "configuration": {
  7
+      "database": "calipso"
  8
+    },
  9
+    "logQueries": false
6 10
   },
7 11
   "server": {
8 12
     "name":"Calipso",
4  lib/core/Form.js
@@ -1096,9 +1096,9 @@ me.mapFields = function(fields, record) {
1096 1096
 
1097 1097
   var props = Object.getOwnPropertyNames(fields);
1098 1098
   props.forEach( function(name) {
1099  
-    // If not private (e.g. _id), then copy
  1099
+    // If not private (e.g. id), then copy
1100 1100
     if(!name.match(/^_.*/)) {
1101  
-      record.set(name, fields[name]);
  1101
+      record[name] = fields[name];
1102 1102
     }
1103 1103
   });
1104 1104
 
2  lib/core/Lib.js
@@ -16,7 +16,7 @@ module.exports = {
16 16
     express: require('express'),
17 17
     step: require('step'),
18 18
     util: require('util'),
19  
-    mongoose: require('mongoose'),
  19
+    jugglingdb: require('jugglingdb'),
20 20
     url: require('url'),
21 21
     ejs: require('ejs'),
22 22
     pager: require(rootpath + 'utils/pager'),
147  lib/core/SessionStorage.js
... ...
@@ -0,0 +1,147 @@
  1
+/**
  2
+ * Module dependencies.
  3
+ */
  4
+
  5
+var Store = require('connect').session.Store,
  6
+    _ = require('underscore'),
  7
+    jugglingdb = require('jugglingdb');
  8
+
  9
+/**
  10
+ * Initialize a new `JugglingStore`.
  11
+ *
  12
+ * @api public
  13
+ */
  14
+
  15
+var JugglingStore = module.exports = function JugglingStore(dbType, dbConfig) {
  16
+  this.db = new jugglingdb.Schema(dbType, dbConfig);
  17
+  this.db.define('Session', {
  18
+    sid: String,
  19
+    data: String
  20
+  });
  21
+};
  22
+
  23
+/**
  24
+ * Inherit from `Store.prototype`.
  25
+ */
  26
+
  27
+JugglingStore.prototype.__proto__ = Store.prototype;
  28
+
  29
+/**
  30
+ * Attempt to fetch session by the given `sid`.
  31
+ *
  32
+ * @param {String} sid
  33
+ * @param {Function} fn
  34
+ * @api public
  35
+ */
  36
+
  37
+JugglingStore.prototype.get = function(sid, fn){
  38
+  var self = this;
  39
+  process.nextTick(function(){
  40
+
  41
+    var Session = self.db.models.Session;
  42
+
  43
+    Session.findOne({where:{sid:sid}}, function (err, sess) {
  44
+      var expires;
  45
+      if (!err && sess && sess.data) {
  46
+        var sessData = JSON.parse(sess.data);
  47
+        expires = 'string' == typeof sessData.cookie.expires
  48
+          ? new Date(sessData.cookie.expires)
  49
+          : sessData.cookie.expires;
  50
+        if (!expires || new Date < expires) {
  51
+          fn(null, sessData);
  52
+        } else {
  53
+          sess.destroy(fn);
  54
+        }
  55
+      } else {
  56
+        fn();
  57
+      }
  58
+    })
  59
+  });
  60
+};
  61
+
  62
+/**
  63
+ * Commit the given `sess` object associated with the given `sid`.
  64
+ *
  65
+ * @param {String} sid
  66
+ * @param {Session} sess
  67
+ * @param {Function} fn
  68
+ * @api public
  69
+ */
  70
+
  71
+JugglingStore.prototype.set = function(sid, sess, fn){
  72
+  var self = this;
  73
+  process.nextTick(function(){
  74
+    var Session = self.db.models.Session;
  75
+    Session.findOne({where:{sid:sid}}, function(err, session) {
  76
+      if(err) {
  77
+        fn(err);
  78
+        return;
  79
+      }
  80
+      if(!session) session = new Session({sid:sid, data:'{}'});
  81
+
  82
+      var sessData = JSON.parse(session.data) || {};
  83
+      _.extend(sessData, sess);
  84
+      session.data = JSON.stringify(sessData);
  85
+
  86
+      session.save(fn);
  87
+    })
  88
+  });
  89
+};
  90
+
  91
+/**
  92
+ * Destroy the session associated with the given `sid`.
  93
+ *
  94
+ * @param {String} sid
  95
+ * @api public
  96
+ */
  97
+
  98
+JugglingStore.prototype.destroy = function(sid, fn){
  99
+  var self = this;
  100
+  process.nextTick(function(){
  101
+    self.db.models.Session.findOne({where:{sid:sid}}, function(err, sess) {
  102
+      if(err) fn(err);
  103
+      if(sess) sess.destroy(fn);
  104
+      else fn();
  105
+    })
  106
+  });
  107
+};
  108
+
  109
+/**
  110
+ * Invoke the given callback `fn` with all active sessions.
  111
+ *
  112
+ * @param {Function} fn
  113
+ * @api public
  114
+ */
  115
+
  116
+JugglingStore.prototype.all = function(fn){
  117
+  var arr = []
  118
+  this.db.models.Session.all({},function(err, sessions) {
  119
+    if (err) fn(err);
  120
+    for(sess in sessions) {
  121
+      arr.push(sess.sid);
  122
+    }
  123
+    fn(null, arr);
  124
+  });
  125
+};
  126
+
  127
+/**
  128
+ * Clear all sessions.
  129
+ *
  130
+ * @param {Function} fn
  131
+ * @api public
  132
+ */
  133
+
  134
+JugglingStore.prototype.clear = function(fn){
  135
+  this.db.models.Session.destroyAll(fn||function() {});
  136
+};
  137
+
  138
+/**
  139
+ * Fetch number of sessions.
  140
+ *
  141
+ * @param {Function} fn
  142
+ * @api public
  143
+ */
  144
+
  145
+JugglingStore.prototype.length = function(fn){
  146
+  this.db.models.Session.count({}, fn||function() {});
  147
+};
125  lib/core/Storage.js
... ...
@@ -1,16 +1,16 @@
1 1
 /*!
2  
- * Calipso MongoDB Storage Library
  2
+ * Calipso DB Storage Library
3 3
  * Copyright(c) 2011 Clifton Cunningham
4 4
  * MIT Licensed
5 5
  *
6  
- * This library provides a few simple functions that can be used to help manage MongoDB and Mongoose.
  6
+ * This library provides a few simple functions that can be used to help manage JugglingDB.
7 7
  */
8 8
 
9 9
 var rootpath = process.cwd(),
10 10
   path = require('path'),
11 11
   events = require('events'),
12  
-  mongoStore = require('connect-mongodb'),
13  
-  mongoose = require('mongoose'),
  12
+  jugglingdb = require('jugglingdb'),
  13
+  SessionStorage = require('./SessionStorage'),
14 14
   calipso = require(path.join('..', 'calipso'));
15 15
 
16 16
 function Storage() {
@@ -19,91 +19,98 @@ function Storage() {
19 19
 }
20 20
 
21 21
 /**
22  
- * Check that the mongodb instance specified in the configuration is valid.
  22
+ * Check that the database instance specified in the configuration is valid.
23 23
  */
24  
-Storage.prototype.mongoConnect = function(dbUri, checkInstalling, next) {
  24
+Storage.prototype.connect = function(dbType, config, checkInstalling, next) {
25 25
 
26  
-  // Test the mongodb configuration
  26
+  // Test the db configuration
27 27
   var isInstalled = calipso.config.get('installed');
28 28
 
29  
-  // If first option is callback, ste dbUri to config value
30  
-  if (typeof dbUri === "function") {
31  
-    next = dbUri;
32  
-    dbUri = calipso.config.get('database:uri');
  29
+  // If first option is callback, set dbType to config value
  30
+  if (typeof dbType === "function") {
  31
+    next = dbType;
  32
+    dbType = 'memory';
33 33
     checkInstalling = false;
34 34
   }
35 35
 
36 36
   // Check we are installing ...
37 37
   if (checkInstalling) {
38  
-    var db = mongoose.createConnection(dbUri, function(err) {
  38
+    try {
  39
+      var db = new jugglingdb.Schema(dbType, config);
  40
+      db.on('connected', function () {
  41
+        next(null, true);
  42
+      })
  43
+    }
  44
+    catch(err) {
39 45
       next(err, false);
40  
-    });
  46
+    }
41 47
     return;
42 48
   }
43 49
 
44 50
   if (isInstalled) {
45 51
 
46  
-    // Always disconnect first just in case any left overs from installation
47  
-    mongoose.disconnect(function() {
48  
-
49  
-      // TODO - what the hell is going on with mongoose?
50  
-      calipso.db = mongoose.createConnection(dbUri, function(err) {
51  
-
52  
-        if (err) {
53  
-
54  
-          calipso.error("Unable to connect to the specified database ".red + dbUri + ", the problem was: ".red + err.message);
55  
-          mongoose.disconnect(function() {
56  
-            return next(err, false);
57  
-          });
58  
-
59  
-        } else {
60  
-
61  
-          calipso.silly("Database connection to " + dbUri + " was successful.");
62  
-
63  
-          // Replace the inmemory session with mongodb backed one
64  
-          var foundMiddleware = false, mw;
65  
-
66  
-          calipso.app.stack.forEach(function(middleware, key) {
67  
-            if (middleware.handle.tag === 'session') {
68  
-              foundMiddleware = true;
69  
-              var maxAge = calipso.config.get('session:maxAge');
70  
-              if (maxAge) {
71  
-                try {
72  
-                  maxAge = Number(maxAge) * 1000;
73  
-                }
74  
-                catch (e) {
75  
-                  calipso.error('MaxAge value ' + maxAge + ' is not a numeric string');
76  
-                  maxAge = undefined;
77  
-                }
  52
+      try {
  53
+        calipso.db = new jugglingdb.Schema(dbType, config);
  54
+        // To maintain compatibility
  55
+        calipso.db.model = function (model) {
  56
+          return calipso.db.models[model];
  57
+        }
  58
+      }
  59
+      catch(err) {
  60
+        calipso.error("Unable to connect to the specified database ".red + dbType + ", the problem was: ".red + err.message);
  61
+        next(err, false);
  62
+        return;
  63
+      }
  64
+      calipso.db.on('connected',function () {
  65
+
  66
+        calipso.silly("Database connection to " + dbType + " was successful.");
  67
+
  68
+        // Replace the inmemory session with database backed one
  69
+        var foundMiddleware = false, mw;
  70
+
  71
+        calipso.app.stack.forEach(function(middleware, key) {
  72
+          if (middleware.handle.tag === 'session') {
  73
+            foundMiddleware = true;
  74
+
  75
+            var maxAge = calipso.config.get('session:maxAge');
  76
+            if (maxAge) {
  77
+              try {
  78
+                maxAge = Number(maxAge) * 1000;
  79
+              }
  80
+              catch (e) {
  81
+                calipso.error('MaxAge value ' + maxAge + ' is not a numeric string');
  82
+                maxAge = undefined;
78 83
               }
  84
+            }
  85
+
  86
+            var store = new SessionStorage(dbType, config);
  87
+            store.db.on('connected', function() {
79 88
               mw = calipso.lib.express.session({
80 89
                 secret: calipso.config.get('session:secret'),
81  
-                store: calipso.app.sessionStore = new mongoStore({
82  
-                  db: calipso.db.db
83  
-                }),
84  
-                cookie: { maxAge: maxAge }
  90
+                store: store,
  91
+                cookie: {maxAge: maxAge}
85 92
               });
86 93
               mw.tag = 'session';
87 94
               calipso.app.stack[key].handle = mw;
88  
-            }
89  
-          });
90  
-
91  
-          if (!foundMiddleware) {
92  
-            return next(new Error("Unable to load the MongoDB backed session, please check your session and db configuration"), false);
  95
+            });
93 96
           }
  97
+        });
94 98
 
95  
-          return next(null, true);
96  
-
  99
+        if (!foundMiddleware) {
  100
+          return next(new Error("Unable to load the Database backed session, please check your session and db configuration"), false);
97 101
         }
  102
+
  103
+        return next(null, true);
  104
+
98 105
       });
99  
-    });
  106
+
100 107
 
101 108
   } else {
102 109
 
103  
-    calipso.silly("Database connection not attempted to " + dbUri + " as in installation mode.");
  110
+    calipso.silly("Database connection not attempted to " + dbType + " as in installation mode.");
104 111
 
105 112
     // Create a dummy connection to enable models to be defined
106  
-    calipso.db = mongoose.createConnection('');
  113
+    calipso.db = new jugglingdb.Schema('memory');
107 114
 
108 115
     next(null, false);
109 116
 
3  lib/core/Table.js
@@ -147,7 +147,8 @@ function getHeaderClass(table, column) {
147 147
 }
148 148
 
149 149
 /**
150  
- * Convert a sortBy parameter into mongo sort queries
  150
+ * Convert a sortBy parameter into db sort queries
  151
+ * TODO: convert to JugglingDB
151 152
  */
152 153
 CalipsoTable.prototype.sortQuery = function(qry, sortBy) {
153 154
 
2  lib/core/Utils.js
@@ -64,7 +64,7 @@ module.exports = {
64 64
 
65 65
     var fields = _.keys(schema.paths);
66 66
     _.each(fields, function(key) {
67  
-      if (key !== '_id') copy.set(key, object.get(key));
  67
+      if (key !== 'id') copy.set(key, object.get(key));
68 68
     });
69 69
 
70 70
   },
78  modules/core/admin/admin.js
@@ -117,7 +117,7 @@ function init(module, app, next) {
117 117
     // Default installation routers - only accessible in install mode
118 118
     module.router.addRoute('GET /admin/install', install, null, this.parallel());
119 119
     module.router.addRoute('POST /admin/install', install, null, this.parallel());
120  
-    module.router.addRoute('POST /admin/installTest/mongo', installMongoTest, null, this.parallel());
  120
+    module.router.addRoute('POST /admin/installTest/db', installDbTest, null, this.parallel());
121 121
     module.router.addRoute('POST /admin/installTest/user', installUserTest, null, this.parallel());
122 122
 
123 123
   }, function done() {
@@ -232,8 +232,8 @@ function install(req, res, template, block, next) {
232 232
         case "welcome":
233 233
           installWelcome(req,res,localNext);
234 234
           break;
235  
-        case "mongodb":
236  
-          installMongo(req,res,localNext);
  235
+        case "db":
  236
+          installDb(req,res,localNext);
237 237
           break;
238 238
         case "user":
239 239
           installUser(req,res,localNext);
@@ -288,38 +288,47 @@ function installWelcome(req,res,next) {
288 288
 }
289 289
 
290 290
 /**
291  
- * Installation mongodb - called by install router, not a routing function.
  291
+ * Installation db - called by install router, not a routing function.
292 292
  */
293  
-function installMongo(req,res,next) {
  293
+function installDb(req,res,next) {
294 294
 
295 295
   // Manually grab the template
296  
-  var template = calipso.modules.admin.templates.install_mongo;
  296
+  var template = calipso.modules.admin.templates.install_db;
297 297
 
298 298
   // Create the form
299  
-  var mongoForm = {id:'install-mongo-form',title:'',type:'form',method:'POST',action:'/admin/install',
  299
+  var dbForm = {id:'install-db-form',title:'',type:'form',method:'POST',action:'/admin/install',
300 300
         fields:[
301  
-          {label:'MongoDB URI',name:'database:uri',cls:'database-uri', type:'text',description:'Enter the database URI, in the form: mongodb://servername:port/database'},
  301
+          {label:'Type', name:'database:type',cls:'database-type', type:'select', options:['mongodb','mongoose','postgres','mysql','riak','redis','couchdb','memory']}, // TODO : Select based on available
  302
+          {label:'Host',name:'database:configuration:host',cls:'database-host', type:'text',description:'Enter the database hostname'},
  303
+          {label:'Port',name:'database:configuration:port',cls:'database-port', type:'text',description:'Enter the database port'},
  304
+          {label:'Username',name:'database:configuration:user',cls:'database-user', type:'text',description:'Enter the database username'},
  305
+          {label:'Password',name:'database:configuration:password',cls:'database-password', type:'password',description:'Enter the database password'},
  306
+          {label:'Database',name:'database:configuration:database',cls:'database-database', type:'text',description:'Enter the database name'},
302 307
           {label:'',name:'installStep',type:'hidden'}
303 308
         ],
304 309
         buttons:[]}; // Submitted via template
305 310
 
306 311
   var formValues = {
307 312
     database: {
308  
-        uri: calipso.config.get('database:uri')
  313
+        type: calipso.config.get('database:type'),
  314
+        host: calipso.config.get('database:configuration:host'),
  315
+        port: calipso.config.get('database:configuration:port'),
  316
+        user: calipso.config.get('database:configuration:user'),
  317
+        password: calipso.config.get('database:configuration:password'),
  318
+        database: calipso.config.get('database:configuration:database')
309 319
     },
310 320
     'installStep':'user'
311 321
   }
312 322
 
313  
-  calipso.form.render(mongoForm, formValues, req, function(form) {
314  
-      calipso.theme.renderItem(req, res, template, 'admin.install.mongo', {form:form}, next);
  323
+  calipso.form.render(dbForm, formValues, req, function(form) {
  324
+      calipso.theme.renderItem(req, res, template, 'admin.install.db', {form:form}, next);
315 325
   });
316  
-
317 326
 }
318 327
 
319 328
 /**
320  
- * Function to enable ajax testing of the mongo configuration
  329
+ * Function to enable ajax testing of the db configuration
321 330
  */
322  
-function installMongoTest(req, res, template, block, next) {
  331
+function installDbTest(req, res, template, block, next) {
323 332
 
324 333
   if (calipso.config.get('installed')) {
325 334
       res.format = "json";
@@ -327,27 +336,22 @@ function installMongoTest(req, res, template, block, next) {
327 336
   }
328 337
 
329 338
   calipso.form.process(req,function(form) {
330  
-    
331  
-    var dbUri = form.dbUri;
  339
+
  340
+    var dbType = form.type;
  341
+    var config = form;
  342
+    delete config.type;
332 343
     var output = {};
333 344
 
334  
-    if(dbUri) {
335  
-      calipso.storage.mongoConnect(dbUri,true,function(err,connected) {
336  
-        if(!err) {
337  
-          output.status = "OK";
338  
-        } else {
339  
-          output.status = "FAILED";
340  
-          output.message= "Failed to connect to MongoDB because: " + err.message;
341  
-        }
342  
-        res.format = "json";
343  
-        res.end(JSON.stringify(output),"UTF-8");
344  
-      });      
345  
-    } else {
346  
-      output.status = "FAILED";
347  
-      output.message= "You need to provide a valid database uri, in the format described.";      
  345
+    calipso.storage.connect(dbType,config,true,function(err,connected) {
  346
+      if(!err) {
  347
+        output.status = "OK";
  348
+      } else {
  349
+        output.status = "FAILED";
  350
+        output.message= "Failed to connect to database because: " + err.message;
  351
+      }
348 352
       res.format = "json";
349 353
       res.end(JSON.stringify(output),"UTF-8");
350  
-    }
  354
+    });
351 355
 
352 356
   });
353 357
 }
@@ -392,7 +396,7 @@ function installUser(req,res,next) {
392 396
 }
393 397
 
394 398
 /**
395  
- * Function to enable ajax testing of the mongo configuration
  399
+ * Function to enable ajax testing of the db configuration
396 400
  */
397 401
 function installUserTest(req, res, template, block, next) {
398 402
 
@@ -497,7 +501,7 @@ function doInstallation(req, res, next) {
497 501
     
498 502
   // Set the install flag to true, enable db connection
499 503
   calipso.config.set('installed',true);
500  
-  calipso.storage.mongoConnect(function(err) {
  504
+  calipso.storage.connect(function(err) {
501 505
       
502 506
     if(err) {
503 507
       return next(err);
@@ -532,7 +536,13 @@ function doInstallation(req, res, next) {
532 536
       
533 537
          modulesToInstall.forEach(function(module){
534 538
           calipso.info("Installing module " + module);
535  
-          calipso.modules[module].fn.install(group());            
  539
+          try {
  540
+            calipso.modules[module].fn.install(group());
  541
+          }
  542
+          catch (err) {
  543
+            calipso.error("Module '"+module+ "' was unable to be installed... Reason: "+err.message);
  544
+          }
  545
+          
536 546
         });
537 547
 
538 548
       },
26  modules/core/admin/templates/install_mongo.html → modules/core/admin/templates/install_db.html
@@ -23,13 +23,13 @@
23 23
 </div>
24 24
 
25 25
 <div class="admin-body">
26  
-  <h2><%= t("Step 1: Configure MongoDB") %></h2>
  26
+  <h2><%= t("Step 1: Configure Database") %></h2>
27 27
 
28  
-  <div id="mongo-status" style="display: none;">
  28
+  <div id="db-status" style="display: none;">
29 29
 
30 30
   </div>
31 31
   
32  
-  <p>To store content, we need to connect to MongoDB. Please provide the location of your database here:
  32
+  <p>To store content, we need to connect to a database:
33 33
 
34 34
   <%- form %>
35 35
   <footer class="admin-install-links">
@@ -45,27 +45,27 @@
45 45
       
46 46
           if(window.jQuery){
47 47
             
48  
-            // Ajax request to /admin/install/mongo/test
49  
-            function checkMongo() {
  48
+            // Ajax request to /admin/install/db/test
  49
+            function checkDb() {
50 50
               
51  
-              $('#mongo-status').show();
52  
-              $('.submit').html("Connecting to MongoDB ...").addClass("loading");
  51
+              $('#db-status').show();
  52
+              $('.submit').html("Connecting to Database ...").addClass("loading");
53 53
               
54  
-              var dbUri = $(".database-uri").val();
55  
-              var postData = {"dbUri":dbUri};
  54
+              var type = $(".database-type").val();
  55
+              var postData = {"type":type};
56 56
               
57 57
               $.ajax({
58 58
                 type: "POST",
59  
-                url: "/admin/installTest/mongo",
  59
+                url: "/admin/installTest/db",
60 60
                 dataType:"json",
61 61
                 data:postData,
62 62
                 success: function(res){
63 63
                   if(res.status === "OK") {
64 64
                     setTimeout(function() {
65  
-                      $('#install-mongo-form').submit();
  65
+                      $('#install-db-form').submit();
66 66
                     }, 1500);
67 67
                   } else {
68  
-                    $('#mongo-status').html("<div class='error'>MongoDB connection failed, please check the details and try again.</div>");
  68
+                    $('#db-status').html("<div class='error'>Database connection failed, please check the details and try again.</div>");
69 69
                     $('.submit').html("Create Database").addClass("loading");
70 70
                   }
71 71
                 }
@@ -74,7 +74,7 @@
74 74
       
75 75
             $('#form-submit').click(function(event) {
76 76
               event.preventDefault();
77  
-              checkMongo();
  77
+              checkDb();
78 78
             });
79 79
           
80 80
           } else {
4  modules/core/admin/templates/install_user.html
@@ -33,7 +33,7 @@
33 33
   <%- form %>
34 34
 
35 35
   <footer class="admin-install-links">
36  
-    <a class="button back" href="?installStep=mongodb"><%= t("Change Database") %></a>
  36
+    <a class="button back" href="?installStep=db"><%= t("Change Database") %></a>
37 37
     <a id="form-submit" class="button next" href="#"><%= t("Create Admin") %></a>
38 38
   </footer>
39 39
 
@@ -45,7 +45,7 @@
45 45
     
46 46
     if(window.jQuery){
47 47
 
48  
-      // Ajax request to /admin/install/mongo/test
  48
+      // Ajax request to /admin/install/user/test
49 49
       function checkUser() {
50 50
         
51 51
         $('#user-status').show();
2  modules/core/admin/templates/install_welcome.html
@@ -15,7 +15,7 @@
15 15
   </ol>
16 16
 
17 17
   <footer class="admin-install-links">
18  
-    <a class="step_1 button next" href="?installStep=mongodb"><%= t("Let's Begin") %></a>
  18
+    <a class="step_1 button next" href="?installStep=db"><%= t("Let's Begin") %></a>
19 19
   </footer>
20 20
 
21 21
 </div>
88  modules/core/content/content.js
@@ -6,7 +6,6 @@
6 6
 var rootpath = process.cwd() + '/',
7 7
   path = require('path'),
8 8
   calipso = require(path.join(rootpath, 'lib/calipso')),
9  
-  Query = require("mongoose").Query,
10 9
   utils = require('connect').utils,
11 10
   merge = utils.merge;
12 11
 
@@ -91,32 +90,30 @@ function init(module,app,next) {
91 90
         calipso.helpers.addHelper('getContentList', function() { return getContentList; });
92 91
 
93 92
         // Default Content Schema
94  
-        var Content = new calipso.lib.mongoose.Schema({
95  
-          title:{type: String, required: true, "default": ''},
96  
-          teaser:{type: String, required: false, "default": ''},
97  
-          taxonomy:{type: String, "default":''},
98  
-          content:{type: String, required: false, "default":''},
99  
-          status:{type: String, required: false, "default":'draft', index: true},
100  
-          alias:{type: String, required: true, index: true},
101  
-          author:{type: String, required: true},
102  
-          etag:{type: String, "default":''},
103  
-          tags:[String],
104  
-          published: { type: Date },
105  
-          scheduled: { type: Date },
106  
-          created: { type: Date, "default": Date.now },
107  
-          updated: { type: Date, "default": Date.now },
108  
-          contentType:{type: String},  // Copy from content type
109  
-          layout:{type: String},       // Copy from content type
110  
-          ispublic:{type: Boolean, index: true}    // Copy from content type
  93
+        var Content = calipso.db.define('Content', {
  94
+          title:        {type: String, required: true, "default": ''},
  95
+          teaser:       {type: String, required: false, "default": ''},
  96
+          taxonomy:     {type: String, "default":''},
  97
+          content:      {type: String, required: false, "default":''},
  98
+          status:       {type: String, required: false, "default":'draft', index: true},
  99
+          alias:        {type: String, required: true, index: true},
  100
+          author:       {type: String, required: true},
  101
+          etag:         {type: String, "default":''},
  102
+          tags:         {type: Array},
  103
+          published:    { type: Date },
  104
+          scheduled:    { type: Date },
  105
+          created:      { type: Date, "default": Date.now },
  106
+          updated:      { type: Date, "default": Date.now },
  107
+          contentType:  {type: String},  // Copy from content type
  108
+          layout:       {type: String},       // Copy from content type
  109
+          ispublic:     {type: Boolean, index: true}    // Copy from content type
111 110
         });
112 111
 
113 112
         // Set post hook to enable simple etag generation
114  
-        Content.pre('save', function (next) {
  113
+        Content.beforeSave = function (next) {
115 114
           this.etag = calipso.lib.crypto.etag(this.title + this.teaser + this.content);
116 115
           next();
117  
-        });
118  
-
119  
-        calipso.db.model('Content', Content);
  116
+        };
120 117
 
121 118
         next();
122 119
 
@@ -154,7 +151,7 @@ function getContent(req, options, next) {
154 151
 
155 152
   var Content = calipso.db.model('Content');
156 153
 
157  
-  Content.findOne({alias:options.alias},function (err, c) {
  154
+  Content.findOne({where:{alias:options.alias}},function (err, c) {
158 155
 
159 156
       if(err || !c) {
160 157
 
@@ -178,9 +175,9 @@ function getContent(req, options, next) {
178 175
 
179 176
         if(options.property) {
180 177
 
181  
-          var text = c.get(options.property) || req.t("Invalid content property: {property}",{property:options.property});
  178
+          var text = c[options.property] || req.t("Invalid content property: {property}",{property:options.property});
182 179
           if(options.clickEdit && req.session && req.session.user && req.session.user.isAdmin) {
183  
-            text = "<span title='" + req.t("Double click to edit content block ...") + "' class='content-block' id='" + c._id + "'>" +
  180
+            text = "<span title='" + req.t("Double click to edit content block ...") + "' class='content-block' id='" + c.id + "'>" +
184 181
             text + "</span>";
185 182
           }
186 183
 
@@ -270,7 +267,7 @@ function createContent(req,res,template,block,next) {
270 267
           var returnTo = form.returnTo ? form.returnTo : "";
271 268
 
272 269
           // Get content type
273  
-          ContentType.findOne({contentType:form.content.contentType}, function(err, contentType) {
  270
+          ContentType.findOne({where:{contentType:form.content.contentType}}, function(err, contentType) {
274 271
 
275 272
 
276 273
               if(err || !contentType) {
@@ -311,7 +308,7 @@ function createContent(req,res,template,block,next) {
311 308
                         if(returnTo) {
312 309
                           res.redirect(returnTo);
313 310
                         } else {
314  
-                          res.redirect('/content/show/' + c._id);
  311
+                          res.redirect('/content/show/' + c.id);
315 312
                         }
316 313
                         next();
317 314
                       });
@@ -361,10 +358,10 @@ function getForm(req,action,title,contentType,next) {
361 358
   // Get content type
362 359
   var ContentType = calipso.db.model('ContentType');
363 360
 
364  
-  ContentType.findOne({contentType:contentType}, function(err, ct) {
  361
+  ContentType.findOne({where:{contentType:contentType}}, function(err, ct) {
365 362
 
366 363
     // Add any fields
367  
-    if(!err && ct && ct.get("fields")) { // FIX as this added later, get is 'safer' if not existing in document
  364
+    if(!err && ct && ct["fields"]) { // FIX as this added later, get is 'safer' if not existing in document
368 365
 
369 366
       var fields = [];
370 367
 
@@ -507,7 +504,7 @@ function editContentForm(req,res,template,block,next) {
507 504
   res.menu.adminToolbar.addMenuItem(req, {name:'Delete',weight:4,path:'delete',url:'/content/delete/' + id,description:'Delete content ...',permit:dPerm});
508 505
 
509 506
 
510  
-  Content.findById(id, function(err, c) {
  507
+  Content.find(id, function(err, c) {
511 508
 
512 509
     if(err || c === null) {
513 510
 
@@ -560,7 +557,7 @@ function updateContent(req,res,template,block,next) {
560 557
         var returnTo = form.returnTo ? form.returnTo : "";
561 558
         var id = req.moduleParams.id;
562 559
 
563  
-        Content.findById(id, function(err, c) {
  560
+        Content.find(id, function(err, c) {
564 561
           if (c) {
565 562
 
566 563
               // Default mapper
@@ -572,7 +569,7 @@ function updateContent(req,res,template,block,next) {
572 569
               c.tags = form.content.tags ? form.content.tags.replace(/[\s]+/g, "").split(",") : [];
573 570
 
574 571
               // Get content type
575  
-              ContentType.findOne({contentType:form.content.contentType}, function(err, contentType) {
  572
+              ContentType.findOne({where:{contentType:form.content.contentType}}, function(err, contentType) {
576 573
 
577 574
                   if(err || !contentType) {
578 575
                     req.flash('error',req.t('Could not save content as I was unable to locate content type {type}.',{type:form.content.contentType}));
@@ -658,7 +655,7 @@ function showAliasedContent(req, res, template, block, next) {
658 655
 
659 656
     var Content = calipso.db.model('Content');
660 657
 
661  
-    Content.findOne({alias:alias},function (err, content) {
  658
+    Content.findOne({where:{alias:alias}},function (err, content) {
662 659
 
663 660
         if(err || !content) {
664 661
           // Create content if it doesn't exist
@@ -676,7 +673,7 @@ function showAliasedContent(req, res, template, block, next) {
676 673
               next(err);
677 674
             } else {
678 675
               // Add the user display details to content
679  
-              content.set('displayAuthor',userDetails);
  676
+              content.displayAuthor = userDetails;
680 677
               showContent(req,res,template,block,next,err,content,format);
681 678
             }
682 679
           });
@@ -703,7 +700,8 @@ function showContentByID(req,res,template,block,next) {
703 700
   var id = req.moduleParams.id;
704 701
   var format = req.moduleParams.format ? req.moduleParams.format : 'html';
705 702
 
706  
-  Content.findById(id, function(err, content) {
  703
+  Content.find(id, function(err, content) {
  704
+
707 705
     // Error locating content
708 706
     if(err) {
709 707
       res.statusCode = 500;
@@ -719,7 +717,7 @@ function showContentByID(req,res,template,block,next) {
719 717
             next(err);
720 718
           } else {
721 719
             // Add the user display details to content
722  
-            content.set('displayAuthor',userDetails);
  720
+            content.displayAuthor = userDetails;
723 721
             showContent(req,res,template,block,next,err,content,format);
724 722
           }
725 723
 
@@ -807,18 +805,18 @@ function listContent(req,res,template,block,next) {
807 805
       var t3 = req.moduleParams.t3 ? req.moduleParams.t3 : '';
808 806
       var t4 = req.moduleParams.t4 ? req.moduleParams.t4 : '';
809 807
 
810  
-      var query = new Query();
  808
+      var query = {where:{}};
811 809
 
812 810
       if(req.session && req.session.user && vPerm(req.session.user)) {
813 811
         // Show all
814 812
       } else {
815 813
         // Published only if not admin
816  
-        query.where('status','published');
  814
+        query.where.status = 'published';
817 815
       }
818 816
 
819 817
       if(tag) {
820 818
         res.layout = "tagLanding" // Enable landing page layout to be created for a tag view
821  
-        query.where('tags',tag);
  819
+        query.where.tags = tag;
822 820
       }
823 821
 
824 822
       // Taxonomy tags
@@ -838,7 +836,7 @@ function listContent(req,res,template,block,next) {
838 836
       }
839 837
 
840 838
       if(taxonomy) {
841  
-        query.where('taxonomy',new RegExp(taxonomy));
  839
+        query.where.taxonomy = new RegExp(taxonomy);
842 840
       }
843 841
 
844 842
     // Get the content list
@@ -851,7 +849,7 @@ function listContent(req,res,template,block,next) {
851 849
  * Helper function for link to user
852 850
  */
853 851
 function contentLink(req, content) {
854  
-  return calipso.link.render({id:content._id,title:req.t('View {content}',{content:content.title}),label:content.title,url:'/content/show/' + content._id});
  852
+  return calipso.link.render({id:content.id,title:req.t('View {content}',{content:content.title}),label:content.title,url:'/content/show/' + content.id});
855 853
 }
856 854
 
857 855
 /**
@@ -884,12 +882,10 @@ function getContentList(query,out,next) {
884 882
           pagerHtml = calipso.lib.pager.render(from,limit,total,out.req.url);
885 883
         }
886 884
 
887  
-        var qry = Content.find(query).skip(from).limit(limit);
888  
-
889 885
         // Add sort
890 886
         // qry = calipso.table.sortQuery(qry, out.sortBy);
891 887
 
892  
-        qry.find(function (err, contents) {
  888
+        var qry = Content.all({skip:from,limit:limit}, function (err, contents) {
893 889
 
894 890
                 if(out && out.res) {
895 891
 
@@ -947,12 +943,12 @@ function deleteContent(req,res,template,block,next) {
947 943
   var Content = calipso.db.model('Content');
948 944
   var id = req.moduleParams.id;
949 945
 
950  
-  Content.findById(id, function(err, c) {
  946
+  Content.find(id, function(err, c) {
951 947
 
952 948
     // Raise CONTENT_CREATE event
953 949
     calipso.e.pre_emit('CONTENT_DELETE',c);
954 950
 
955  
-    Content.remove({_id:id}, function(err) {
  951
+    c.destroy(function(err) {
956 952
       if(err) {
957 953
         req.flash('info',req.t('Unable to delete the content because {msg}',{msg:err.message}));
958 954
         res.redirect("/");
2  modules/core/content/templates/listAdmin.html
@@ -8,7 +8,7 @@
8 8
 </tr>
9 9
 <% contents.forEach(function(item) { %>
10 10
 <tr class='content-list-item content-list-item-<%- item.status %> content-type-<%- item.contentType %>'>
11  
-    <td><a href='/content/show/<%= item._id %>'><%- item.title %></a></td>
  11
+    <td><a href='/content/show/<%= item.id %>'><%- item.title %></a></td>
12 12
     <td><%- item.contentType %></td>
13 13
     <td><%- item.author %></td>
14 14
     <td><%- prettyDate(item.published) %></td>
21  modules/core/contentTypes/contentTypes.js
@@ -6,8 +6,7 @@
6 6
 
7 7
 var rootpath = process.cwd() + '/',
8 8
   path = require('path'),
9  
-  calipso = require(path.join(rootpath, 'lib/calipso')),
10  
-  Query = require("mongoose").Query;
  9
+  calipso = require(path.join(rootpath, 'lib/calipso'));
11 10
 
12 11
 /**
13 12
  * Define the routes that this module will repsond to.
@@ -76,7 +75,7 @@ function init(module,app,next) {
76 75
   calipso.permission.Helper.addPermission("admin:content:type","Content Types",true);
77 76
 
78 77
   // Schemea
79  
-  var ContentType = new calipso.lib.mongoose.Schema({
  78
+  var ContentType = calipso.db.define('ContentType', {
80 79
     contentType:{type: String, required: true, unique: true, "default": 'default', index: true},
81 80
     description:{type: String, required: true, "default": 'Default Content Type'},
82 81
     layout:{type: String, required: true, "default": 'default'},
@@ -89,8 +88,6 @@ function init(module,app,next) {
89 88
     listTemplate:{type: String, "default": ''},        
90 89
   });
91 90
 
92  
-  calipso.db.model('ContentType', ContentType);
93  
-
94 91
   // Cache the content types in the calipso.data object
95 92
   if(app.config.get('installed')) {
96 93
     storeContentTypes(null,null,function(){});
@@ -340,7 +337,7 @@ function showContentType(req,res,template,block,next) {
340 337
       res.menu.adminToolbar.addMenuItem(req, {name:'Edit',path:'edit',url:'/content/type/edit/' + id,description:'Edit content type ...',permit:calipso.permission.Helper.hasPermission("admin:content:type:edit")});
341 338
       res.menu.adminToolbar.addMenuItem(req, {name:'Delete',path:'delete',url:'/content/type/delete/' + id,description:'Delete content type ...',permit:calipso.permission.Helper.hasPermission("admin:content:type:delete")});
342 339
 
343  
-      item = {id:content._id,type:'content',meta:content.toObject()};
  340
+      item = {id:content.id,type:'content',meta:content.toObject()};
344 341
 
345 342
     }
346 343
 
@@ -384,16 +381,12 @@ function listContentType(req,res,template,block,next) {
384 381
 
385 382
   var format = req.moduleParams.format || 'html';
386 383
 
387  
-  var query = new Query();
388  
-
389 384
   // Initialise the block based on our content
390  
-  ContentType.count(query, function (err, count) {
  385
+  ContentType.count({}, function (err, count) {
391 386
 
392 387
     var total = count;
393 388
 
394  
-    ContentType.find(query)
395  
-      .sort('contentType', 1)
396  
-      .find(function (err, contents) {
  389
+    ContentType.all({sort:'contentType'}, function (err, contents) {
397 390
 
398 391
         // Render the item into the response
399 392
         if(format === 'html') {
@@ -428,7 +421,7 @@ function deleteContentType(req,res,template,block,next) {
428 421
 
429 422
     calipso.e.pre_emit('CONTENT_TYPE_DELETE',c);
430 423
 
431  
-    ContentType.remove({_id:id}, function(err) {
  424
+    c.destroy(function(err) {
432 425
       if(err) {
433 426
         req.flash('info',req.t('Unable to delete the content type because {msg}.',{msg:err.message}));
434 427
         res.redirect("/content/type");
@@ -491,7 +484,7 @@ function storeContentTypes(event,contentType,next) {
491 484
   delete calipso.data.contentTypes;
492 485
   calipso.data.contentTypes = [];
493 486
 
494  
-  ContentType.find({}).sort('contentType',1).find(function (err, types) {
  487
+  ContentType.all({order: 'contentType'}, function (err, types) {
495 488
     if(err || !types) {
496 489
       
497 490
       // Don't throw error, just pass back failure.
2  modules/core/contentTypes/templates/list.html
@@ -9,7 +9,7 @@
9 9
         items.forEach(function(item) {
10 10
          %>
11 11
 	         <tr>
12  
-	        <td><a href='/content/type/show/<%- item._id %>'><%- item.contentType %></a></td>
  12
+	        <td><a href='/content/type/show/<%- item.id %>'><%- item.contentType %></a></td>
13 13
 	        <td> <%- item.description %></td>
14 14
 	        <td> <%- item.layout %></td>
15 15
 	        <td> <%- item.ispublic ? "Yes" : "No" %></td>
33  modules/core/contentVersions/contentVersions.js
@@ -7,7 +7,6 @@
7 7
 var rootpath = process.cwd() + '/',
8 8
   path = require('path'),
9 9
   calipso = require(path.join(rootpath, 'lib/calipso')),
10  
-  Query = require('mongoose').Query,
11 10
   diff = require('./support/jsdiff');
12 11
 
13 12
 exports = module.exports = {
@@ -69,13 +68,11 @@ function init(module,app,next) {
69 68
       function done() {
70 69
 
71 70
         // Schema
72  
-        var ContentVersion = new calipso.lib.mongoose.Schema({
  71
+        var ContentVersion = new calipso.db.define('ContentVersion', {
73 72
           contentId:{type: String}
74 73
           // All other properties are dynamically mapped, hence use of .set / .get
75 74
         });
76 75
 
77  
-        calipso.db.model('ContentVersion', ContentVersion);
78  
-
79