database.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. 'use strict';
  2. var JSONStream = require('JSONStream');
  3. var Promise = require('bluebird');
  4. var fs = require('graceful-fs');
  5. var _ = require('lodash');
  6. var Model = require('./model');
  7. var Schema = require('./schema');
  8. var SchemaType = require('./schematype');
  9. var util = require('./util');
  10. var WarehouseError = require('./error');
  11. var pkg = require('../package.json');
  12. var extend = _.assign;
  13. /**
  14. * Database constructor.
  15. *
  16. * @class
  17. * @param {object} [options]
  18. * @param {number} [options.version=0] Database version
  19. * @param {string} [options.path] Database path
  20. * @param {function} [options.onUpgrade] Triggered when the database is upgraded
  21. * @param {function} [options.onDowngrade] Triggered when the database is downgraded
  22. */
  23. function Database(options) {
  24. this.options = extend({
  25. version: 0,
  26. onUpgrade: function() {},
  27. onDowngrade: function() {}
  28. }, options);
  29. this._models = {};
  30. var _Model = this.Model = function(name, schema) {
  31. Model.call(this, name, schema);
  32. };
  33. util.inherits(_Model, Model);
  34. _Model.prototype._database = this;
  35. }
  36. /**
  37. * Creates a new model.
  38. *
  39. * @param {string} name
  40. * @param {Schema|object} [schema]
  41. * @return {Model}
  42. */
  43. Database.prototype.model = function(name, schema) {
  44. if (this._models[name]) {
  45. return this._models[name];
  46. }
  47. var model = this._models[name] = new this.Model(name, schema);
  48. return model;
  49. };
  50. /**
  51. * Loads database.
  52. *
  53. * @param {function} [callback]
  54. * @return {Promise}
  55. */
  56. Database.prototype.load = function(callback) {
  57. var path = this.options.path;
  58. var self = this;
  59. if (!path) throw new WarehouseError('options.path is required');
  60. return new Promise(function(resolve, reject) {
  61. var src = fs.createReadStream(path, {encoding: 'utf8'});
  62. var oldVersion = 0;
  63. var stream = JSONStream.parse([true, true], function(value, keys) {
  64. switch (keys.shift()){
  65. case 'meta':
  66. if (keys.shift() === 'version') {
  67. oldVersion = value;
  68. }
  69. break;
  70. case 'models':
  71. self.model(keys.shift())._import(value);
  72. break;
  73. }
  74. });
  75. src
  76. .pipe(stream)
  77. .on('error', reject)
  78. .on('end', function() {
  79. resolve(oldVersion);
  80. });
  81. }).then(function(oldVersion) {
  82. var newVersion = self.options.version;
  83. if (newVersion > oldVersion) {
  84. return self.options.onUpgrade(oldVersion, newVersion);
  85. } else if (newVersion < oldVersion) {
  86. return self.options.onDowngrade(oldVersion, newVersion);
  87. }
  88. }).asCallback(callback);
  89. };
  90. /**
  91. * Saves database.
  92. *
  93. * @param {function} [callback]
  94. * @return {Promise}
  95. */
  96. Database.prototype.save = function(callback) {
  97. var path = this.options.path;
  98. var self = this;
  99. if (!path) throw new WarehouseError('options.path is required');
  100. return new Promise(function(resolve, reject) {
  101. var stream = fs.createWriteStream(path);
  102. // Start
  103. stream.write('{');
  104. // Meta
  105. stream.write('"meta":' + JSON.stringify({
  106. version: self.options.version,
  107. warehouse: pkg.version
  108. }) + ',');
  109. // Export models
  110. var models = self._models;
  111. var keys = Object.keys(models);
  112. var model, key;
  113. stream.write('"models":{');
  114. for (var i = 0, len = keys.length; i < len; i++) {
  115. key = keys[i];
  116. model = models[key];
  117. if (!model) continue;
  118. if (i) stream.write(',');
  119. stream.write('"' + key + '":' + model._export());
  120. }
  121. stream.write('}');
  122. // End
  123. stream.end('}');
  124. stream.on('error', reject)
  125. .on('finish', resolve);
  126. }).asCallback(callback);
  127. };
  128. Database.Schema = Database.prototype.Schema = Schema;
  129. Database.SchemaType = Database.prototype.SchemaType = SchemaType;
  130. Database.version = pkg.version;
  131. module.exports = Database;