summaryrefslogtreecommitdiff
path: root/app/index.js
blob: 641a468745189510c9972060af97c00a10011217 (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
var path = require('path');
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');

/**
 * OKCMS!
 * Basically takes configuration and gives you a server.
 */
function OKCMS(options) {
  options = options || {};
  var root = this._root = options.root || 'www';
  // Reduce resource config into unique set
  this._resourceConfig = options.resources || [];
  this._views = options.views || {
    '/': { template: 'index' }
  };
  this._resourceRoot = options.resourceRoot || '/api';
  this._server = new OKServer({root: root});
  this._templates = new OKTemplate({root: root});
  var db = this._db = options.db || new OKDB();
  // Special query for getting meta info
  this._meta = options.meta || {
    name: 'meta',
    get: function() {
      return db.getMeta();
    }
  };
  this._init();
}

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

OKCMS.prototype._init = function _init() {
  var self = this;

  // Create resources instances from config and add CRUD views on them
  // NOTE Does not support subresources
  this._resources = this._resourceConfig.map(function (config) {
    var resource = self._createResource(config);
    var route = path.join(self._resourceRoot, resource.name);
    self._server.addView(route, resource.view());
    return resource;
  });

  // Add HTML views
  Object.keys(this._views)
    // Make sure more specific routes are processed first
    // TODO This is not semantically correct (bro)
    .sort(function(a, b) {
      return a.length < b.length;
    })
    // For each route / viewOptions pair, add a view
    .forEach(function eachRoute(route) {
      var options = self._views[route];
      // View should know what its route is.
      options.route = route;
      var view = self._createView(options);
      // Add view at route
      self._server.addView(route, view);
    });
};

/**
 * Takes a resource configuration object and returns a resource instance
 */
OKCMS.prototype._createResource = function(options) {
  options = options || {};
  var resourceClass = options.resource;
  // No resource? Bail!
  if (!resourceClass) throw new Error('OKCMS: No resource class given');
  // Default to 'select all' id
  options.id = options.id || '*';
  // Some dependency injection
  options.db = this._db;
  // Clean unpassed options
  delete options.resource;
  // Return resource instance
  return resourceClass(options);
};

/**
 * Takes a view configuration object and returns a view instance
 */
OKCMS.prototype._createView = function _createView(options) {
  options = options || {};
  var self = this;
  var viewClass = options.view || OKView;
  var template = this._templates.getTemplate(options.template);
  var queryConfig = options.data || [];
  // No template? Bail!
  if (!template) throw new Error('OKCMS: No template "' + options.template + '"');
  // Inject them dependencies
  options.template = template;
  options.meta = this._meta;
  options.queries = this._createQueries(queryConfig);
  // Clean options not passed to view
  delete options.view;
  // Return view instance
  return viewClass(options);
};

/**
 * Takes a query configuration and returns a list of queries
 */
OKCMS.prototype._createQueries = function(options) {
  options = options || [];
  var db = this._db;
  if (!options.length)
    options = [options];
  return options.map(function(option) {
    if (!option.name)
      throw new Error('No document name provided to query');
    option.id = option.id || '*';
    return new OKQuery(db, {
      name: option.name,
      id: option.id
    });
  });
};

module.exports = {

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

  OKResource: OKResource,

  OKView: OKView,

  OKRestEndpoint: OKRestEndpoint

};