nails-boilerplate 1.3.1 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/nails.js CHANGED
@@ -15,14 +15,10 @@ import { EventEmitter } from 'node:events';
15
15
 
16
16
 
17
17
  import Controller from './controller.js';
18
- import Model from './model.js';
19
18
  import ModelV2 from './model_v2.js';
20
19
  import Router from './router.js';
21
20
 
22
21
  import express_app from './application.js';
23
- import DbConnector from './database_connector.js';
24
-
25
- const models = {};
26
22
 
27
23
  // TODO: add key value pairs to express app singleton.
28
24
  var application = {};
@@ -42,7 +38,6 @@ export default async function nails(app_config) {
42
38
  nails.application = express_app;
43
39
  nails.Controller = Controller;
44
40
  nails.Model = ModelV2;
45
- nails.ModelDeprecated = Model;
46
41
  nails.events = new EventEmitter();
47
42
 
48
43
  async function configure( app_config ) {
@@ -75,26 +70,14 @@ async function configure( app_config ) {
75
70
  console.log("Initializing DB connection...");
76
71
  var DBConnector = await get_dbconnector(app_config.db.connector);
77
72
 
78
- // TODO: deprecate the old Model style
79
- if (app_config.config.MODELS_ROOT) {
80
- Model.set_connector(DBConnector, app_config.db);
81
- await init_models(app_config.config.MODELS_ROOT);
82
- }
83
- // TODO: make this Model style mandatory
84
- console.log("Connecting to DB...");
85
- if (DBConnector instanceof DbConnector) {
86
- console.log("Generating model superclass...");
87
- await DBConnector.connect(app_config.db);
88
- ModelV2.setConnector(DBConnector);
89
- await init_models_v2(app_config.config.MODELS_ROOT);
90
- DBConnector.afterInitialization();
91
- } else {
92
- console.log("Instantiating DBConnector...");
93
- // Try to instantiate DBConnector
94
- let dbConnector = new DBConnector();
95
- await dbConnector.connect(app_config.db);
96
- ModelV2.setConnector(dbConnector);
97
- }
73
+ console.log("Instantiating DBConnector and Connecting to DB...");
74
+ // Try to instantiate DBConnector
75
+ let dbConnector = new DBConnector();
76
+ await dbConnector.connect(app_config.db);
77
+ console.log("Generating model superclass...");
78
+ ModelV2.setConnector(dbConnector);
79
+ await init_models_v2(app_config.config.MODELS_ROOT);
80
+ await dbConnector.afterInitialization();
98
81
  console.log("DB Connection complete");
99
82
 
100
83
  // init Controllers
@@ -151,9 +134,9 @@ function startServer(config) {
151
134
  async function init_controllers(controller_lib) {
152
135
  await init_app_lib(Controller, controller_lib);
153
136
  }
154
- async function init_models(model_lib) {
155
- await init_app_lib(Model, model_lib);
156
- }
137
+ // async function init_models(model_lib) {
138
+ // await init_app_lib(Model, model_lib);
139
+ // }
157
140
  async function init_app_lib(superclass, abs_path) {
158
141
  console.log('attempting to import:', abs_path);
159
142
  if (!fs.existsSync(abs_path))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nails-boilerplate",
3
- "version": "1.3.1",
3
+ "version": "2.0.1",
4
4
  "description": "A node.js webserver scaffold",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -1,4 +1,4 @@
1
- import MongoDBConnector from '../lib/mongodb_connector.js';
1
+ import MongooseConnector from '../lib/mongoose_connector.js';
2
2
  import {MongoMemoryServer} from 'mongodb-memory-server';
3
3
 
4
4
  let singularInstanceCreated = false;
@@ -19,7 +19,7 @@ class MongoDBConnectorUtil {
19
19
  const dbConfig =
20
20
  {uri: uri, port: port, database: dbName, dbPath: dbPath};
21
21
  //console.log(JSON.stringify(dbConfig));
22
- return new MongoDBConnector(dbConfig);
22
+ return new MongooseConnector(dbConfig);
23
23
  }
24
24
 
25
25
  async cleanup() {
package/lib/model.js DELETED
@@ -1,167 +0,0 @@
1
- // This is the base definition for a model / collection
2
- // ideally used as a wrapper for database integration
3
- // should use promise objects to allow for method chaining
4
- // eventful. emits ready event passing itself
5
- // start with mongodb
6
- import util from 'util';
7
- import controller_base from './controller.js';
8
- // var controller_base = require('./controller.js');
9
- // var util = require('util');
10
-
11
- /** TODO: what persistence methods does a model need?
12
- * save/post => saves record to db
13
- * fetch/get => updates model from database
14
- * patch/put(?) => only changes specific methods and saves to database...
15
- * destroy/delete => remove model from db
16
- *
17
- ** On Constructor:
18
- *
19
- * get => get a single model by id
20
- * find => get a collection of models by parameters
21
- */
22
- /** TODO: define a collection
23
- *
24
- * will likely want to put collection constructor as attribute on Model
25
- * f/e Model.Collection
26
- *
27
- ** Persistence methods:
28
- *
29
- * save/post => save collection in database by batch command
30
- * will want to minimize number of db requests, but can probably
31
- * start with saving each individually for now
32
- * fetch/get => updates collection from database
33
- * a collection should have a saved query attribute which
34
- * was used to get the collection. Will make updating easy.
35
- */
36
-
37
- // init references to model base objects for use by controllers
38
- // and models
39
- controller_base.prototype.models = {};
40
- Model.prototype.models = {};
41
-
42
- var model_prot = Model.prototype;
43
- var db;
44
-
45
- var NAME_REQUIRED_ERROR = function() {
46
- return new Error(
47
- 'FATAL ERROR::: Named function required for Model constructor method'
48
- );
49
- }
50
-
51
- export default function Model(){
52
- };
53
-
54
- Model.extend = function(constructor) {
55
- //console.log('extending', constructor.name);
56
- if ( !constructor.name ) throw NAME_REQUIRED_ERROR();
57
- //model_proto = model_proto || new Model();
58
- constructor.prototype.__proto__ = model_prot;
59
-
60
- // TODO: bind collection-specific methods to the constructor
61
- //Model.set_db_access_methods(contructor);
62
-
63
- // make models available to controller and other models
64
- Model.prototype.models[constructor.name] = constructor;
65
- controller_base.prototype.models[constructor.name] = constructor;
66
-
67
- };
68
- Model.set_connector = function(DBConnector, config) {
69
- if (!config) {
70
- this.prototype.connector = DBConnector;
71
- } else {
72
- this.prototype.connector = new DBConnector(config);
73
- }
74
- };
75
- Model.set_db_access_methods = function(constructor) {
76
- constructor.find = Model.find;
77
- };
78
- Model.find = function() {
79
- var args = Array.prototype.slice.call(arguments, 0);
80
- return this.connector.find.apply(connector, args);
81
- };
82
-
83
- Object.defineProperty(Model.prototype, 'id', {
84
- get: function() {
85
- return this.attributes[this.id_attribute];
86
- },
87
- set: function(new_val) {
88
- this.set(this.id_attribute, new_val);
89
- return new_val;
90
- }
91
- });
92
- Object.defineProperty(Model.prototype, 'attributes', {
93
- get: function() {
94
- if (!this._attributes) this._attributes = {};
95
- return this._attributes;
96
- },
97
- set: function(new_val) {
98
- if (typeof new_val != 'object' && util.isArray(new_val))
99
- throw 'Model#attributes cannot be set to non-object or array value';
100
- this._extend_deeply(this.attributes, new_val, true);
101
- return this.attributes;
102
- }
103
- });
104
- Model.prototype.id_attribute = '_id';
105
- Model.prototype.is_model = true;
106
- /**
107
- * returns the name of the collection or table in the db.
108
- * override this by setting collection attribute on the model.
109
- */
110
- Model.prototype._collection_name = function() {
111
- return this.collection || this.constructor.name;
112
- };
113
- /**
114
- * pointer to the database connector
115
- */
116
- Model.prototype.connector = {};
117
-
118
- Model.prototype.save = function() {
119
- // this should create the model if it does not exist
120
- // (uses an id to check existence)
121
- // or it should update the model
122
- if (this.id) return this.connector.put(this);
123
- return this.connector.post(this);
124
- };
125
- Model.prototype.fetch = function() {
126
- if (!this.id) throw 'cannot fetch model with id: ' + this.id.toString();
127
- return this.connector.get(this);
128
- // TODO: give model backbone-like sync event
129
- };
130
- /*
131
- Model.prototype.patch = function() {
132
- // should try to update the model's changed attributes if no
133
- // arguments given. Otherwise should attempt to set attributes
134
- // on model and then update
135
- Model.connector.update(this);
136
- };
137
- */
138
- Model.prototype.destroy = function() {
139
- // should delete the model from the database if it has been
140
- // persisted
141
- if (this.id) return false;
142
- this.connector.delete(this);
143
- };
144
- Model.prototype.set = function(attr, val) {
145
- this.attributes[attr] = val;
146
- };
147
- /**
148
- * merge a hash of attributes into the current set
149
- */
150
- Model.prototype._merge_attributes = function(attr) {
151
- this._extend_deeply(this.attributes, attr);
152
- };
153
- Model.prototype._extend_deeply = function(obj0, obj1, should_prune) {
154
- if (typeof obj0 != 'object' || typeof obj1 != 'object' ||
155
- util.isArray(obj0) || util.isArray(obj1))
156
- throw 'Attempting to extend a non-object entity';
157
- for(var key in obj1) {
158
- if (typeof obj0[key] == 'object' && typeof obj1[key] == 'object' && !util.isArray(obj0[key]))
159
- this._extend_deeply(obj0[key], obj1[key], should_prune);
160
- else obj0[key] = obj1[key];
161
- }
162
- if (!should_prune) return;
163
- for (key in obj0) {
164
- if (key in obj1) continue;
165
- delete obj0[key];
166
- }
167
- };
@@ -1,100 +0,0 @@
1
- // TODO: multiple async requests here... need to
2
- // consider how this will be used by the models
3
- import {EventEmitter} from 'node:events';
4
- // var EventEmitter = require('events').EventEmitter;
5
- // const MongoClient = require('mongodb').MongoClient;
6
- import { MongoClient } from 'mongodb';
7
-
8
- export default MongoDBConnector;
9
-
10
- // TODO: need to deal with clustered databases...
11
-
12
- MongoDBConnector.prototype.__proto__ = EventEmitter.prototype;
13
- function MongoDBConnector(config) {
14
- EventEmitter.call(this);
15
- var url = config.url || 'mongodb://localhost';
16
- var port = config.port || '27017';
17
- var database = config.database || 'nails';
18
- var uri =
19
- config.uri ? config.uri : `${url}:${port}/${database}`;
20
- this.exec_once_connected = [];
21
- var that = this;
22
- MongoClient.connect(uri)
23
- .then(client => {
24
- this._client = client;
25
- this._db = client.db(database);
26
- this.emit("connected");
27
- }).catch(error => {
28
- // TODO: better handling of the failed connection
29
- console.error(error);
30
- throw error;
31
- });
32
- }
33
-
34
- /**
35
- * Need to implement these methods for a connector to work
36
- */
37
- // maybe use rest methods as names for any database connector used...
38
- MongoDBConnector.prototype.post = function(model_or_collection) {
39
- if (model_or_collection.is_model)
40
- return this._post_one(model_or_collection._collection_name(),
41
- model_or_collection.attributes);
42
- }
43
- MongoDBConnector.prototype._post_one = function(collection_name, doc_attributes, callback) {
44
- return this._db.collection(collection_name).insert(doc_attributes);
45
- }
46
- MongoDBConnector.prototype._post_many = function(collection) {
47
- return this._db.collection(collection.name())
48
- .save(collection.model_attributes());
49
- }
50
-
51
- // update a record in the collection
52
- MongoDBConnector.prototype.put = function(model_or_collection) {
53
- if (model_or_collection.is_model)
54
- return this._put_one(
55
- model_or_collection._collection_name(),
56
- model_or_collection.attributes);
57
- }
58
- MongoDBConnector.prototype._put_one = function(collection_name, doc) {
59
- // TODO: replacing document completely is sow
60
- // will want to only send changed attr
61
- // TODO: write concerns?
62
- return this._db.collection(collection_name).replaceOne({_id: doc._id}, doc);
63
- }
64
- /**
65
- * _put_many will call _update on each individual object in collection
66
- * if that object has changed
67
- */
68
- MongoDBConnector.prototype._put_many = function(collection) {
69
- }
70
-
71
- // return a single record from a collection
72
- // or a collection of records if requested...
73
- // if a model or collection is passed,
74
- MongoDBConnector.prototype.get = function(model_or_collection) {
75
- if (model_or_collection.is_model)
76
- return this._get_one(model_or_collection._collection_name(), model_or_collection.id, null)
77
- .then(doc => this._on_doc_response(model_or_collection, doc));
78
- }
79
- MongoDBConnector.prototype._get_one = function(collection_name, id, options) {
80
- options = options || {};
81
- return this._db.collection(collection_name).findOne(id, options);
82
- }
83
- MongoDBConnector.prototype._get_many = function(collection) {
84
- return this._db.collection(collection.name()).find({
85
- _id: collection.collect('_id')});
86
- }
87
-
88
- // delete a record from a collection
89
- MongoDBConnector.prototype.delete = function(model) {
90
- return this._db.collection(model.collection_name())
91
- .remove(model.attributes._id);
92
- }
93
- // MongoDBConnector.prototype._delete_one
94
- // MongoDBConnector.prototype._delete_many
95
-
96
- MongoDBConnector.prototype._on_doc_response = function(model_or_collection, doc) {
97
- // move this to the promise catch block: if (err) return console.log('error retrieving from', collection_name, '\n', err);
98
- delete doc._id;
99
- model_or_collection._merge_attributes(doc);
100
- }
@@ -1,88 +0,0 @@
1
- // TODO: multiple async requests here... need to
2
- // consider how this will be used by the models
3
- import { EventEmitter } from 'events';
4
- import DBClient from 'node:sqlite';
5
- // var EventEmitter = require('events').EventEmitter;
6
- // const DBClient = require('sqlite3');
7
- import test from 'node:assert';
8
- // const test = require('assert');
9
-
10
- module.exports = SQLite3Connector;
11
-
12
- // TODO: need to deal with clustered databases...
13
-
14
- SQLite3Connector.prototype.__proto__ = EventEmitter.prototype;
15
- function SQLite3Connector(config) {
16
- EventEmitter.call(this);
17
- var url = config.url || 'mongodb://localhost';
18
- var port = config.port || '27017';
19
- var database = config.database || 'nails';
20
- this.exec_once_connected = [];
21
- this._db = new DBClient.Database(config.filename);
22
- }
23
-
24
- /**
25
- * Need to implement these methods for a connector to work
26
- */
27
- // maybe use rest methods as names for any database connector used...
28
- SQLite3Connector.prototype.post = function(model_or_collection) {
29
- if (model_or_collection.is_model)
30
- this._post_one(model_or_collection._collection_name(),
31
- model_or_collection.attributes);
32
- }
33
- SQLite3Connector.prototype._post_one = function(collection_name, doc_attributes, callback) {
34
- this._db.collection(collection_name).insert(doc_attributes);
35
- }
36
- SQLite3Connector.prototype._post_many = function(collection) {
37
- this._db.collection(collection.name())
38
- .save(collection.model_attributes());
39
- }
40
-
41
- // update a record in the collection
42
- SQLite3Connector.prototype.put = function(model_or_collection) {
43
- if (model_or_collection.is_model)
44
- this._put_one(model_or_collection._collection_name(), model_or_collection.attributes);
45
- }
46
- SQLite3Connector.prototype._put_one = function(collection_name, doc) {
47
- // TODO: replacing document completely is sow
48
- // will want to only send changed attr
49
- // TODO: write concerns?
50
- this._db.collection(collection_name).update({_id: doc._id}, doc);
51
- }
52
- /**
53
- * _put_many will call _update on each individual object in collection
54
- * if that object has changed
55
- */
56
- SQLite3Connector.prototype._put_many = function(collection) {
57
- }
58
-
59
- // return a single record from a collection
60
- // or a collection of records if requested...
61
- // if a model or collection is passed,
62
- SQLite3Connector.prototype.get = function(model_or_collection) {
63
- if (model_or_collection.is_model)
64
- this._get_one(model_or_collection._collection_name(), model_or_collection.id, null,
65
- this._on_doc_response.bind(model_or_collection));
66
- }
67
- SQLite3Connector.prototype._get_one = function(collection_name, id, options, callback) {
68
- options = options || {};
69
- this._db.collection(collection_name).findOne(id, options, callback);
70
- }
71
- SQLite3Connector.prototype._get_many = function(collection) {
72
- return this._db.collection(collection.name()).find({
73
- _id: collection.collect('_id')});
74
- }
75
-
76
- // delete a record from a collection
77
- SQLite3Connector.prototype.delete = function(model) {
78
- return this._db.collection(model.collection_name())
79
- .remove(model.attributes._id);
80
- }
81
- // SQLite3Connector.prototype._delete_one
82
- // SQLite3Connector.prototype._delete_many
83
-
84
- SQLite3Connector.prototype._on_doc_response = function(err, doc) {
85
- if (err) return console.log('error retrieving from', collection_name, '\n', err);
86
- delete doc._id;
87
- this._merge_attributes(doc);
88
- }
@@ -1,95 +0,0 @@
1
- import assert from 'assert';
2
- import Model from '../lib/model.js';
3
- import MongoDBConnectorUtil from './mongodb_connector.util.js';
4
-
5
- var test_model = new Model();
6
- var model_prot = Model.prototype;
7
- describe('Model', function() {
8
- var util;
9
- beforeEach(function(done) {
10
- util = new MongoDBConnectorUtil();
11
- util.getTestConnector().then(connector => {
12
- Model.set_connector(connector);
13
- connector.on("connected", done);
14
- });
15
- });
16
- afterEach(function(done) {
17
- util.cleanup().then(() => done());
18
- });
19
- describe('#_merge_attributes', function() {
20
- });
21
- describe('#_extend_deeply', function() {
22
- var attr0;
23
- var attr1;
24
- beforeEach(function() {
25
- attr0 = {a:7, b:'test', c:null, o: {}};
26
- attr1 = {a:8, c:'test0', o: {a:0}};
27
- });
28
- it('should rewrite non object attributes', function() {
29
- model_prot._extend_deeply(attr0, attr1);
30
- // these should change
31
- assert(attr0.a == attr1.a);
32
- assert(attr0.c == attr1.c);
33
- // these should not
34
- assert(attr0.b == attr0.b);
35
- assert(attr0.o == attr0.o);
36
- });
37
- it('should merge two attributes if they are both non-array objects',
38
- function() {
39
- model_prot._extend_deeply(attr0, attr1);
40
- assert(attr0.o.a == attr1.o.a);
41
- });
42
- it('should delete attributes not present in obj1 if prune is true',
43
- function() {
44
- model_prot._extend_deeply(attr0, attr1, true);
45
- assert(!('b' in attr0));
46
- });
47
- it('should not delete attributes absent present in obj1 if prune is falsey', function() {
48
- model_prot._extend_deeply(attr0, attr1);
49
- assert(attr0.o.a == attr1.o.a);
50
- });
51
- });
52
- describe('#save', function() {
53
- it('should save a new model to the database and update id',
54
- async function() {
55
- var model0 = new Model();
56
- var model_name = 'testname0';
57
- model0.attributes = {
58
- name: model_name
59
- };
60
- await model0.save();
61
- assert.ok(model0.attributes._id);
62
- assert.ok(model_name == model0.attributes.name);
63
- });
64
- it('should save changes to an existing model to the database',
65
- async function() {
66
- var model0 = new Model();
67
- model0.attributes = {
68
- name: 'testname1'
69
- };
70
- await model0.save();
71
- model0.set('x', 5);
72
- await model0.save();
73
- var model1 = new Model();
74
- model1.id = model0.id;
75
- await model1.fetch();
76
- assert.ok(model1.attributes.x == 5);
77
- });
78
- });
79
- describe('#fetch', function() {
80
- it('should retrieve attributes for this model id from the database',
81
- async function() {
82
- var model0 = new Model();
83
- model0.set('x', 7);
84
- await model0.save();
85
- var model1 = new Model();
86
- model1.id = model0.id;
87
- await model1.fetch();
88
- assert.ok(model1.attributes.x == 7);
89
- });
90
- });
91
- describe('#attributes', function() {
92
- it('should be a plain object');
93
- it('should not change by reference if set to a different attributes hash');
94
- });
95
- });
@@ -1,66 +0,0 @@
1
- import assert from 'assert';
2
- import MongoDBConnectorUtil from './mongodb_connector.util.js';
3
-
4
- describe('MongoDBConnector', function() {
5
- var util;
6
- var mdbc;
7
- beforeEach(function(done) {
8
- util = new MongoDBConnectorUtil();
9
- util.getTestConnector().then(connector => {
10
- mdbc = connector;
11
- connector.on("connected", done);
12
- });
13
- });
14
- afterEach(function(done) {
15
- util.cleanup().then(() => done());
16
- });
17
- it('should create a new connection to mongodb', function(done) {
18
- assert.notEqual(mdbc._db, null);
19
- done();
20
- });
21
- describe('#put', function() {
22
- it('should be ok, updating the record in the database');
23
- });
24
- describe('Document retrieval', function() {
25
- describe('#get', function() {
26
- it('should return a single document when model is passed');
27
- it('should return an array of docments when collection is passed');
28
- });
29
- describe('#_get_one', function() {
30
- it('should return a single document with the matching _id', async function() {
31
- var test_model = get_test_model('custom0');
32
- var test_attr = test_model.attributes;
33
- await mdbc._post_one(test_model.collection_name(), test_attr);
34
- let doc = await mdbc._get_one(test_model.collection_name(),
35
- test_model.attributes._id, null);
36
- assert.ok(doc.custom_attr == test_attr.custom_attr);
37
- assert.ok(doc._id.equals(test_attr._id));
38
- return null;
39
- });
40
- });
41
- describe('#_get_many', function() {
42
- it('should return all documents matching the collection._query field');
43
- });
44
- });
45
- describe('Document Creation', function(){
46
- describe('#_post_one', function() {
47
- it('should set an _id attribute on the given attributes hash', function(done) {
48
- var test_model = get_test_model();
49
- mdbc._post_one(test_model.collection_name(), test_model.attributes)
50
- .then(() => {
51
- assert.ok(test_model.attributes._id);
52
- done();
53
- });
54
- });
55
- });
56
- });
57
- });
58
- function get_test_model(custom_attr) {
59
- return {
60
- collection_name: function() {return 'test_model'},
61
- attributes: {
62
- x: 'x',
63
- custom_attr: custom_attr
64
- }
65
- }
66
- }