summaryrefslogtreecommitdiff
path: root/app/index.js
blob: f4e95937ff035d814311ba3228d40d70b880a9a6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
var path = require('path');
var format = require('util').format;
var OKQuery = require('okquery');
var OKView = require('okview');
var OKDB = require('okdb');
var OKResource = require('okresource')
var OKTemplate = require('oktemplate');
var OKServer = require('okserver');
var OKRestEndpoint = require('okrest');
var OKSchema = require('okschema');

/**
 * OKCMS!
 * Basically takes configuration and gives you a server.
 */
function OKCMS(options) {
  options = options || {};
  var root = this._root = options.root || 'www';
  var schemaConfig = options.schemas || {};
  var resourceConfig = options.resources || [];
  var viewConfig = options.views || {
    '/': { template: 'index' }
  };
  // TODO Make configurable
  var db = this._db = new OKDB();
  var templateCache = this._templateCache = new OKTemplate({root: root});
  var server = this._server = new OKServer({root: root});
  // Special query for getting meta info
  var meta = this._meta = {
    name: 'meta',
    get: function() {
      return db.getMeta();
    }
  };
  var schemas = this._schemas = this._createSchemas(schemaConfig);
  var resources = this._resources =
      this._createResources(resourceConfig, db, schemas);
  var views = this._views =
      this._createViews(viewConfig, db, meta, templateCache);
  this._initViews(server, views);
}

OKCMS.prototype.listen = function listen(port, options) {
  options = options || {};
  this._server.listen(port);
};

OKCMS.prototype._createSchemas = function(schemaConfig) {
  schemaConfig = schemaConfig || {};
  return Object.keys(schemaConfig).reduce(function(cache, key) {
    var spec = schemaConfig[key];
    cache[key] = OKSchema(spec);
    return cache;
  }, {});
}

OKCMS.prototype._createResources = function(resourceConfig, db, schemaCache) {
  resourceConfig = resourceConfig || {};
  return resourceConfig.map(function(config) {
    var type = config.type;
    var schema = schemaCache[type];
    if (!schema)
      throw new Error('Resource config references nonexistent schema');
    // If no id is provided, default to "select all"
    var id = config.id || '*';
    return OKResource({
      type: type,
      id: id,
      schema: schema
    })
  });
};

OKCMS.prototype._createViews = function(viewConfig, db,
    meta, templateCache) {
  viewConfig = viewConfig || {};
  var self = this;
  var createQueries = this._createQueries.bind(this);
  return Object.keys(viewConfig).reduce(function(cache, route) {
    var config = viewConfig[route];
    var templateName = config.template || getDefaultTemplate(route, config);
    var template = templateCache.getTemplate(templateName);
    if (!template)
      throw new Error(format('No template named "%s" found', templateName));
    var queryConfig = config.data || [];
    var queries = createQueries(queryConfig, db);
    // Instantiate!
    cache[route] = OKView({
      route: route,
      template: template,
      queries: queries,
      meta: meta
    });
    return cache;
  }, {});

  /**
   * Returns the default template for a view config
   */
  function getDefaultTemplate(route, config) {
    // Root route defaults to index
    if (/^\/?$/.test(route))
      return 'index';
    // Otherwise default to the backing resource name
    else if (config && config.data && config.data.type)
      return config.data.type;
    // Otherwise dunno
    else
      return '404';
  }
}

OKCMS.prototype._createQueries = function(queryConfig, db) {
  queryConfig = queryConfig || {};
  if (!queryConfig.length)
    queryConfig = [queryConfig];
  return queryConfig.map(function(config) {
    // Default to "select all" query
    var id = config.id || '*';
    return new OKQuery(db, {
      type: config.type,
      id: id
    });
  });
};

OKCMS.prototype._initViews = function(server, views) {
  Object.keys(views)
      // Make sure more specific routes are processed first
      // TODO This is not semantically correct (bro)
      //      Will prob manifest bugs
      .sort(function(a, b) {
        return a.length < b.length;
      })
      // Add the views
      .forEach(function(route) {
        server.addView(route, views[route]);
      });
};

module.exports = {

  createApp: function(options) {
    return new OKCMS(options);
  },

  OKResource: OKResource,

  OKView: OKView,

  OKRestEndpoint: OKRestEndpoint

};