Permalink
Browse files

initial commit

  • Loading branch information...
0 parents commit b53d91a0ee41752cd9af8c59277868feded9c69a @dgf committed Mar 16, 2012
Showing with 383 additions and 0 deletions.
  1. +2 −0 .gitignore
  2. +31 −0 Cakefile
  3. +119 −0 lib/c3store.js
  4. +29 −0 package.json
  5. +29 −0 spec/c3store.spec.coffee
  6. +4 −0 spec/checker.coffee
  7. +50 −0 spec/in-memory-store.coffee
  8. +8 −0 spec/in-memory-store.spec.coffee
  9. +54 −0 spec/store.spec.template.coffee
  10. +57 −0 src/c3store.coffee
@@ -0,0 +1,2 @@
+.idea/
+node_modules
@@ -0,0 +1,31 @@
+fs = require 'fs'
+{print} = require 'util'
+{spawn} = require 'child_process'
+jasmineBinary = './node_modules/jasmine-node/bin/jasmine-node'
+
+# ANSI Terminal Colors
+bold = '\033[0;1m'
+green = '\033[0;32m'
+reset = '\033[0m'
+red = '\033[0;31m'
+
+log = (message, color) -> console.log color + message + reset
+
+call = (name, options, callback) ->
+ proc = spawn name, options
+ proc.stdout.on 'data', (data) -> print data.toString()
+ proc.stderr.on 'data', (data) -> log data.toString(), red
+ proc.on 'exit', callback
+
+build = (callback) -> call 'coffee', ['-c', '-o', 'lib', 'src'], callback
+
+spec = (callback) -> call jasmineBinary, ['spec', '--coffee'], callback
+
+task 'build', 'build coffee', ->
+ build (status) -> log ":)", green if status is 0
+
+task 'spec', 'run specifications', ->
+ build (buildStatus) ->
+ if buildStatus is 0
+ spec (testStatus) ->
+ log ":)", green if testStatus is 0
@@ -0,0 +1,119 @@
+(function() {
+ var C3Store, Sequelize, SessionModel, crudl, _;
+
+ Sequelize = require('sequelize');
+
+ crudl = require('crudl-model');
+
+ _ = require('underscore');
+
+ SessionModel = {
+ sid: {
+ type: Sequelize.STRING,
+ allowNull: false,
+ unique: true,
+ validate: {
+ notEmpty: true
+ }
+ },
+ data: {
+ type: Sequelize.TEXT,
+ allowNull: false,
+ validate: {
+ notEmpty: true
+ }
+ }
+ };
+
+ C3Store = (function() {
+
+ function C3Store(SequelizeSession) {
+ this.SequelizeSession = SequelizeSession;
+ this.Session = crudl(this.SequelizeSession);
+ }
+
+ C3Store.prototype.clear = function(callback) {
+ var error, success;
+ success = function() {
+ return typeof callback === "function" ? callback() : void 0;
+ };
+ error = function(error) {
+ return typeof callback === "function" ? callback(error) : void 0;
+ };
+ return this.Session.clear(success, error);
+ };
+
+ C3Store.prototype.destroy = function(sid, callback) {
+ var error, q, success;
+ success = function() {
+ return typeof callback === "function" ? callback() : void 0;
+ };
+ error = function(error) {
+ return typeof callback === "function" ? callback(error) : void 0;
+ };
+ q = {
+ where: {
+ sid: sid
+ }
+ };
+ return this.Session["delete"](q, success, error);
+ };
+
+ C3Store.prototype.length = function(callback) {
+ var error, success;
+ success = function(count) {
+ return typeof callback === "function" ? callback(count) : void 0;
+ };
+ error = function(error) {
+ return typeof callback === "function" ? callback(null) : void 0;
+ };
+ return this.Session.count(success, error);
+ };
+
+ C3Store.prototype.get = function(sid, callback) {
+ var error, q, success;
+ success = function(session) {
+ if (session) {
+ return typeof callback === "function" ? callback(null, JSON.parse(session.data)) : void 0;
+ } else {
+ return typeof callback === "function" ? callback('session not found') : void 0;
+ }
+ };
+ error = function(error) {
+ return typeof callback === "function" ? callback(error) : void 0;
+ };
+ q = {
+ where: {
+ sid: sid
+ }
+ };
+ return this.Session.find(q, success, error);
+ };
+
+ C3Store.prototype.set = function(sid, session, callback) {
+ var error, s, success;
+ s = {
+ sid: sid,
+ data: JSON.stringify(session)
+ };
+ success = function(session) {
+ return typeof callback === "function" ? callback() : void 0;
+ };
+ error = function(error) {
+ return typeof callback === "function" ? callback(error) : void 0;
+ };
+ return this.Session.create(s, success, error);
+ };
+
+ return C3Store;
+
+ })();
+
+ module.exports = function(connect) {
+ C3Store.prototype.__proto__ = connect.session.Store.prototype;
+ return function(sequelize, model) {
+ return new C3Store(sequelize.define('Session', _.extend(SessionModel, model)));
+ };
+ };
+
+}).call(this);
@@ -0,0 +1,29 @@
+{
+ "author": "Danny Gräf <github@dagnu.de>"
+ , "name": "c3store"
+ , "description": "connect Sequelize session store"
+ , "version": "0.0.1"
+ , "homepage": "http://github.com/dgf/c3store"
+ , "repository": {
+ "type": "git"
+ , "url": "git@github.com:dgf/c3store.git"
+ }
+ , "main": "lib/c3store.js"
+ , "scripts": {
+ "pretest": "cake build"
+ , "prepublish": "cake build"
+ , "test": "cake spec"
+ }
+ , "engines": {
+ "node": "~0.6.7"
+ }
+ , "dependencies": {
+ "coffee-script": "1.2.x"
+ , "crudl-model": "0.0.x"
+ }
+ , "devDependencies": {
+ "connect": "1.8.x"
+ , "jasmine-node": "1.0.x"
+ , "sqlite3": "2.1.x"
+ }
+}
@@ -0,0 +1,29 @@
+connect = require('connect')
+Sequelize = require 'sequelize'
+
+aCheck = require './checker'
+C3Store = require('../src/c3store') connect
+spec = require './store.spec.template'
+
+describe 'Sequelize session store implementation', ->
+ db = new Sequelize 'checkfoo', 'root', '', logging: false
+
+ # @todo write spec to use sqlite
+ # in Database#all('SELECT * FROM `Sessions` WHERE `sid`=\'sid1\' LIMIT 1;', [Function])
+ # => SyntaxError: Unexpected token \
+ #db = new Sequelize 'session-store', 'sa', 'secret',
+ # logging: false,
+ # dialect: 'sqlite'
+ # storage: 'foo.db'
+ # storage: ':memory:'
+
+ spec (sessions) ->
+ store = new C3Store db, optional: type: Sequelize.STRING
+ sync = (done) -> store.SequelizeSession.sync(force: true).success(done)
+ aCheck 'sync model', sync, 50
+
+ for own sid of sessions
+ do (sid) -> aCheck 'save session', (done) ->
+ store.set sid, sessions[sid], done
+
+ store
@@ -0,0 +1,4 @@
+module.exports = (message, test, timeout = 20) ->
+ isDone = false
+ runs -> test -> isDone = true
+ waitsFor (-> isDone), message, timeout
@@ -0,0 +1,50 @@
+SID_PATTERN = /sid(\d)/
+
+ifSidMatches = (sid, error, success) -> # error hook base
+ if not SID_PATTERN.test sid
+ error? 'invalid sid format'
+ else
+ success()
+
+class InMemorySessionStore
+
+ constructor: (options) ->
+ @sessions = []
+ @getBySid = (sid) -> @sessions[parseInt sid.match(SID_PATTERN)[1]]
+
+ clear: (callback) ->
+ if @sessions?
+ @sessions = []
+ callback()
+ else
+ callback 'clear call failed'
+
+ destroy: (sid, callback) ->
+ ifSidMatches sid, callback, =>
+ session = @getBySid(sid)
+ if session?
+ delete session
+ callback?()
+ else
+ callback? 'session not found'
+
+ length: (callback) ->
+ if @sessions? then callback @sessions.length else callback null
+
+ get: (sid, callback) ->
+ ifSidMatches sid, callback, =>
+ session = @getBySid(sid)
+ if session?
+ callback null, session # return data
+ else
+ callback 'nothing found'
+
+ set: (sid, session, callback) ->
+ ifSidMatches sid, callback, =>
+ @sessions.push session
+ callback?()
+
+
+module.exports = (connect) ->
+ InMemorySessionStore:: __proto__ = connect.session.Store.prototype
+ InMemorySessionStore
@@ -0,0 +1,8 @@
+spec = require './store.spec.template'
+MemStore = require('./in-memory-store') require('connect')
+
+describe 'in memory session store implementation', ->
+ spec (sessions) ->
+ store = new MemStore
+ store.set sid, sessions[sid] for own sid of sessions
+ store
@@ -0,0 +1,54 @@
+# connect middleware session store interface specification
+_ = require 'underscore'
+aCheck = require './checker'
+
+# attention: stateful test spec, beware of right order
+module.exports = (createStore) ->
+ sessions =
+ sid0: { data: key: 'a session' }
+ sid1: { data: key: 'another one' }
+
+ store = createStore sessions
+
+ it 'extends connect.session.Store.prototype', ->
+ expect(store.createSession).toBeDefined 'inherits session create method'
+
+ it 'defines get(sid, callback)', =>
+ aCheck 'get a session', (done) ->
+ store.get 'sid1', (error, session) ->
+ expect(error).toBeNull 'no error'
+ expect(_.isEqual session, sessions.sid1).toBeTruthy 'session one'
+ done()
+
+ aCheck 'get unknown session', (done) ->
+ store.get 'sid3', (error, session) ->
+ expect(error).toBeDefined 'an error'
+ expect(session).toBeUndefined 'no session'
+ done()
+
+ it 'defines set(sid, session, callback)', =>
+ aCheck 'set session without callback', (done) ->
+ store.set 'sid2', { data: key: 'third session' }, done
+
+ it 'defines length(callback)', ->
+ aCheck 'get session count', (done) ->
+ store.length (count) ->
+ expect(count).toBe 3, 'sessions length'
+ done()
+
+ it 'defines destroy(sid, callback)', =>
+ aCheck 'destroy session one', (done) ->
+ store.destroy 'sid1', (error) ->
+ expect(error).toBeUndefined 'no error'
+ done()
+
+ aCheck 'destroy unknown session', (done) ->
+ store.destroy 'sid3', (error) ->
+ expect(error).toBeDefined 'an error'
+ done()
+
+ it 'defines clear(callback)', ->
+ aCheck 'clear store', (done) ->
+ store.clear (error) ->
+ expect(error).toBeUndefined 'no error'
+ done()
@@ -0,0 +1,57 @@
+Sequelize = require 'sequelize'
+crudl = require 'crudl-model'
+_ = require 'underscore'
+
+SessionModel =
+ sid:
+ type: Sequelize.STRING
+ allowNull: false
+ unique: true
+ validate: notEmpty: true
+ data:
+ type: Sequelize.TEXT
+ allowNull: false
+ validate: notEmpty: true
+
+# connect middleware session implementation
+class C3Store
+
+ constructor: (@SequelizeSession) ->
+ @Session = crudl @SequelizeSession
+
+ clear: (callback) ->
+ success = -> callback?()
+ error = (error) -> callback? error
+ @Session.clear success, error
+
+ destroy: (sid, callback) ->
+ success = -> callback?()
+ error = (error) -> callback? error
+ q = where: sid: sid
+ @Session.delete q, success, error
+
+ length: (callback) ->
+ success = (count) -> callback? count
+ error = (error) -> callback? null
+ @Session.count success, error
+
+ get: (sid, callback) ->
+ success = (session) ->
+ if session
+ callback? null, JSON.parse session.data
+ else
+ callback? 'session not found'
+ error = (error) -> callback? error
+
+ q = where: sid: sid
+ @Session.find q, success, error
+
+ set: (sid, session, callback) ->
+ s = sid: sid, data: JSON.stringify session
+ success = (session) -> callback?()
+ error = (error) -> callback? error
+ @Session.create s, success, error
+
+module.exports = (connect) ->
+ C3Store:: __proto__ = connect.session.Store.prototype
+ (sequelize, model) -> new C3Store sequelize.define 'Session', _.extend(SessionModel, model)

0 comments on commit b53d91a

Please sign in to comment.