nails-boilerplate 1.3.1 → 2.0.2
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 +16 -29
- package/lib/sequelize_connector.js +1 -1
- package/package.json +1 -1
- package/spec/mongodb_connector.util.js +2 -2
- package/spec/services/integration_sequelize/README.md +5 -0
- package/spec/services/integration_sequelize/client/css/styles.css +0 -0
- package/spec/services/integration_sequelize/client/download.jpg +0 -0
- package/spec/services/integration_sequelize/client/favicon.ico +0 -0
- package/spec/services/integration_sequelize/client/index.html +9 -0
- package/spec/services/integration_sequelize/client/js/client.js +0 -0
- package/spec/services/integration_sequelize/client/js/components/app.jsx +15 -0
- package/spec/services/integration_sequelize/config/db.js +4 -0
- package/spec/services/integration_sequelize/config/mimes.js +61 -0
- package/spec/services/integration_sequelize/config/routes.js +25 -0
- package/spec/services/integration_sequelize/config/service.js +48 -0
- package/spec/services/integration_sequelize/config/ssl/certificate.pem +22 -0
- package/spec/services/integration_sequelize/config/ssl/csr.csr +17 -0
- package/spec/services/integration_sequelize/config/ssl/key.pem +28 -0
- package/spec/services/integration_sequelize/config/ssl/private_key.pem +30 -0
- package/spec/services/integration_sequelize/config/ssl/public_key.pem +9 -0
- package/spec/services/integration_sequelize/package.json +23 -0
- package/spec/services/integration_sequelize/server/controllers/default_json_controller.js +21 -0
- package/spec/services/integration_sequelize/server/controllers/home_controller.js +39 -0
- package/spec/services/integration_sequelize/server/models/dog.js +7 -0
- package/spec/services/integration_sequelize/server/models/owner.js +10 -0
- package/spec/services/integration_sequelize/server/views/defaultjson/testnojson.ejs +1 -0
- package/spec/services/integration_sequelize/server/views/testreact/testreact.ejs +15 -0
- package/spec/services/integration_sequelize/server.js +9 -0
- package/spec/services.integration_sequelize.spec.js +67 -0
- package/templates/config/service.js +1 -1
- package/lib/model.js +0 -167
- package/lib/mongodb_connector.js +0 -100
- package/lib/sqlite3_connector.js +0 -88
- package/spec/model.spec.js +0 -95
- package/spec/mongodb_connector.spec.js +0 -66
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,8 +38,8 @@ 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();
|
|
42
|
+
nails._dbConnector = null;
|
|
47
43
|
|
|
48
44
|
async function configure( app_config ) {
|
|
49
45
|
express_app.set('nails_config', application);
|
|
@@ -75,26 +71,16 @@ async function configure( app_config ) {
|
|
|
75
71
|
console.log("Initializing DB connection...");
|
|
76
72
|
var DBConnector = await get_dbconnector(app_config.db.connector);
|
|
77
73
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
-
}
|
|
74
|
+
console.log("Instantiating DBConnector and Connecting to DB...");
|
|
75
|
+
// Try to instantiate DBConnector
|
|
76
|
+
const dbConnector = new DBConnector();
|
|
77
|
+
nails._dbConnector = dbConnector;
|
|
78
|
+
await dbConnector.connect(app_config.db);
|
|
79
|
+
console.log("Generating model superclass...");
|
|
80
|
+
ModelV2.setConnector(dbConnector);
|
|
81
|
+
await init_models_v2(app_config.config.MODELS_ROOT);
|
|
82
|
+
console.log("Done importing models")
|
|
83
|
+
await dbConnector.afterInitialization();
|
|
98
84
|
console.log("DB Connection complete");
|
|
99
85
|
|
|
100
86
|
// init Controllers
|
|
@@ -151,9 +137,9 @@ function startServer(config) {
|
|
|
151
137
|
async function init_controllers(controller_lib) {
|
|
152
138
|
await init_app_lib(Controller, controller_lib);
|
|
153
139
|
}
|
|
154
|
-
async function init_models(model_lib) {
|
|
155
|
-
|
|
156
|
-
}
|
|
140
|
+
// async function init_models(model_lib) {
|
|
141
|
+
// await init_app_lib(Model, model_lib);
|
|
142
|
+
// }
|
|
157
143
|
async function init_app_lib(superclass, abs_path) {
|
|
158
144
|
console.log('attempting to import:', abs_path);
|
|
159
145
|
if (!fs.existsSync(abs_path))
|
|
@@ -183,7 +169,8 @@ async function init_models_v2(abs_path) {
|
|
|
183
169
|
// We just need to import each model once so the generateSuperclass
|
|
184
170
|
// method is called at least once for each model.
|
|
185
171
|
let modelClass = (await import(abs_path)).default;
|
|
186
|
-
console.log('imported model:', modelClass.name);
|
|
172
|
+
if (modelClass && modelClass.name) console.log('imported model:', modelClass.name);
|
|
173
|
+
else console.warn("No model found at:", abs_path);
|
|
187
174
|
// // Constructor function was provided
|
|
188
175
|
// if (!superclass.isPrototypeOf(subclass))
|
|
189
176
|
// return superclass.extend(subclass);
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
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
|
|
22
|
+
return new MongooseConnector(dbConfig);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
async cleanup() {
|
|
File without changes
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Use frontend React components to build a single-page webapp
|
|
2
|
+
class App extends React.Component {
|
|
3
|
+
render() {
|
|
4
|
+
return (
|
|
5
|
+
<div>
|
|
6
|
+
Successfully rendered your homepage!
|
|
7
|
+
</div>
|
|
8
|
+
);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
ReactDOM.render(
|
|
13
|
+
<App />,
|
|
14
|
+
document.getElementById('app')
|
|
15
|
+
);
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file uses file extensions in the request to determine
|
|
3
|
+
* the type of an asset and, therefore, where it can be found
|
|
4
|
+
* in the file system.
|
|
5
|
+
*
|
|
6
|
+
* Currently, the supported types are: 'js', 'css', 'html',
|
|
7
|
+
* 'img'
|
|
8
|
+
* TODO: Add supported types pdf ( or document ), and video
|
|
9
|
+
* TODO: move this file into nails. Too annoying for the dev
|
|
10
|
+
* to see and they shouldn't need to have to change it
|
|
11
|
+
*/
|
|
12
|
+
/*
|
|
13
|
+
var mimes = {
|
|
14
|
+
// <ext>: '<type>'
|
|
15
|
+
js: 'js',
|
|
16
|
+
jpg: 'image',
|
|
17
|
+
css: 'css',
|
|
18
|
+
html: 'html'
|
|
19
|
+
};
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
var mimes = {
|
|
23
|
+
html: {
|
|
24
|
+
type: 'page',
|
|
25
|
+
contentType: 'text/html'
|
|
26
|
+
},
|
|
27
|
+
js: {
|
|
28
|
+
type: 'script', // the type of the script,
|
|
29
|
+
contentType: 'application/javascript' // Header info
|
|
30
|
+
},
|
|
31
|
+
css: {
|
|
32
|
+
type: 'style',
|
|
33
|
+
contentType: 'text/css'
|
|
34
|
+
},
|
|
35
|
+
ico: {
|
|
36
|
+
type: 'image',
|
|
37
|
+
contentType: 'image/x-icon'
|
|
38
|
+
},
|
|
39
|
+
jpg: {
|
|
40
|
+
type: 'image',
|
|
41
|
+
contentType: 'image/jpeg'
|
|
42
|
+
},
|
|
43
|
+
png: {
|
|
44
|
+
type: 'image',
|
|
45
|
+
contentType: 'image/png'
|
|
46
|
+
},
|
|
47
|
+
pdf: {
|
|
48
|
+
type: 'document',
|
|
49
|
+
contentType: 'application/pdf'
|
|
50
|
+
},
|
|
51
|
+
xml: {
|
|
52
|
+
type: 'data',
|
|
53
|
+
contentType: 'text/xml'
|
|
54
|
+
},
|
|
55
|
+
json: {
|
|
56
|
+
type: 'data',
|
|
57
|
+
contentType: 'application/json'
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export default mimes;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Routes specifies the array of route definitions to be passed to the router
|
|
3
|
+
*
|
|
4
|
+
* Routes are checked in series, and the first matching route is applied.
|
|
5
|
+
* A route definition is as follows:
|
|
6
|
+
* ['METHOD', 'MATCHER', 'OPTIONS']
|
|
7
|
+
*
|
|
8
|
+
* METHOD => crud methods (GET, PUT, POST, DELETE)
|
|
9
|
+
* MATCHER => to be matched against the path. Captured elements will be passed to options. Delegates to express application routing.
|
|
10
|
+
* OPTIONS => an object with parametes deciding how the route will be handled in order of execution:
|
|
11
|
+
* path: => the path to a static file ( index.html f/e)
|
|
12
|
+
* controller: => controller to route the request to. TODO: May implement a resource definition for automatically routing cruds
|
|
13
|
+
* action: => the method to run in the controller. If not specified, the index method will be called.
|
|
14
|
+
* [1..n]: => each numerical definition defines a parameter in which to store the value of the captured elements in the regex.
|
|
15
|
+
* controller, and action are protected names and will apply the cature to controller name and method respectively.
|
|
16
|
+
* f/e: ['get', /\/(home)/, {0: 'controller'}] => routes to home controller
|
|
17
|
+
* ['get, '/\/home\/(5)/, {controller: 'home', 0: 'id'}] => routes to home controller and adds {id: 5} to the params hash.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
var routes = [
|
|
21
|
+
// Routes the root request to index.html, as well as all other requests to static
|
|
22
|
+
['get', "/", {controller: 'home'}],
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
export default routes;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Initializes application before server starts
|
|
2
|
+
// Each of these is REQUIRED
|
|
3
|
+
|
|
4
|
+
import routes from './routes.js';
|
|
5
|
+
import mimes from './mimes.js';
|
|
6
|
+
import db from './db.js';
|
|
7
|
+
|
|
8
|
+
var SERVER_ROOT = import.meta.dirname + '/..';
|
|
9
|
+
var APP_ROOT = SERVER_ROOT + '/server';
|
|
10
|
+
|
|
11
|
+
// Only for reading the certificates for SSL
|
|
12
|
+
import fs from 'node:fs';
|
|
13
|
+
// const fs = require('fs');
|
|
14
|
+
const PRIVATE_KEY_FILE = fs.readFileSync(`${import.meta.dirname}/ssl/key.pem`);
|
|
15
|
+
const CERTIFICATE_FILE = fs.readFileSync(`${import.meta.dirname}/ssl/certificate.pem`);
|
|
16
|
+
|
|
17
|
+
var config = {
|
|
18
|
+
APP_ROOT: APP_ROOT,
|
|
19
|
+
// root directory for delivering static assets
|
|
20
|
+
PUBLIC_ROOT: SERVER_ROOT + '/client',
|
|
21
|
+
CONTROLLERS_ROOT: APP_ROOT + '/controllers',
|
|
22
|
+
VIEWS_ROOT: APP_ROOT + '/views',
|
|
23
|
+
MODELS_ROOT: APP_ROOT + '/models',
|
|
24
|
+
SERVER_ROOT: SERVER_ROOT,
|
|
25
|
+
|
|
26
|
+
ENABLE_HTTP: true,
|
|
27
|
+
//IP: "0.0.0.0",
|
|
28
|
+
PORT: 3333,
|
|
29
|
+
|
|
30
|
+
ASYNC: false,
|
|
31
|
+
|
|
32
|
+
// For HTTPS
|
|
33
|
+
ENABLE_HTTPS: true,
|
|
34
|
+
SSL_PORT: 3334,
|
|
35
|
+
PRIVATE_KEY: PRIVATE_KEY_FILE,
|
|
36
|
+
CERTIFICATE: CERTIFICATE_FILE,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// module.exports.routes = require('./routes.js');
|
|
40
|
+
// module.exports.mimes = require('./mimes.js');
|
|
41
|
+
// module.exports.db = require('./db.js');
|
|
42
|
+
|
|
43
|
+
export default {
|
|
44
|
+
config,
|
|
45
|
+
routes,
|
|
46
|
+
db,
|
|
47
|
+
mimes,
|
|
48
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
MIIDrzCCApegAwIBAgIUR04h3qlfhW5SYQrnm0VjDSLQrwUwDQYJKoZIhvcNAQEL
|
|
3
|
+
BQAwZzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQ4wDAYDVQQKDAVOYWlsczES
|
|
4
|
+
MBAGA1UEAwwJbG9jYWxob3N0MScwJQYJKoZIhvcNAQkBFhhhZG1pbkBwcm9qZWN0
|
|
5
|
+
aW52aWN0YS5jb20wHhcNMjMwODMwMDE1MzUzWhcNMjQwODI5MDE1MzUzWjBnMQsw
|
|
6
|
+
CQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExDjAMBgNVBAoMBU5haWxzMRIwEAYDVQQD
|
|
7
|
+
DAlsb2NhbGhvc3QxJzAlBgkqhkiG9w0BCQEWGGFkbWluQHByb2plY3RpbnZpY3Rh
|
|
8
|
+
LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALP54rGDg1Lo7FSs
|
|
9
|
+
q4xvvOeisWLJzbTZN+hsxL3ytcxvk3oidVoZDDfkDJ1QBoPFjIyHlJZCvC6mJMeY
|
|
10
|
+
3Nibn1zZAtsST84DCYS8c0bQAbEUc+OwSmNpVLQElnTAKyoY/7izj579p5uR7WLD
|
|
11
|
+
mSk2c4igeqjOAQn/rrC3Lr+Dr6HA3lcEQD7g87OQz7JCRY6p5E980HO81gknnxod
|
|
12
|
+
veQogbreiQ+MOwC9qPOwfJjAX/qkTWc1SXIiV2SskoIANTbGujMHZZZIaY5a5oWZ
|
|
13
|
+
9pAKR0basSAjECMmr1/UCKGZeot0AZRKMBSHp6mlHlE5LLFIH56PaRTguSBhsrle
|
|
14
|
+
BWcuUcUCAwEAAaNTMFEwHQYDVR0OBBYEFCigQMRd+cKymXdHgew3JMEcokv0MB8G
|
|
15
|
+
A1UdIwQYMBaAFCigQMRd+cKymXdHgew3JMEcokv0MA8GA1UdEwEB/wQFMAMBAf8w
|
|
16
|
+
DQYJKoZIhvcNAQELBQADggEBAD5ZtQ3XLBzOiJoICcRA0evC/59gt2kKw1owOLJy
|
|
17
|
+
Ji4rtoWCis8nr3R1U62KUENZ//WRy09uNPHfjsaFwuvgO+GWn53Q3breCEO1r2lH
|
|
18
|
+
z5qWUAdb7WpoZWZJdj6wZoJQeKQoK8fVCVNNPNHwhZRK2P2SWhn5v/7Qco5JMP8+
|
|
19
|
+
qpIbAzjKOoHiz1238JYXJ5G1tMVMfVvQpC1E+KM9p9Bohtuc51pYMssT31WPBoOv
|
|
20
|
+
TBcIarZ8ri6VBAh/+aUpce0BqOEtZ1oa6Mnd2w5GeqgtV+G7ir5g0uXZjOFrh5A7
|
|
21
|
+
c6J3QmpeF3kfs+Ggsxh/fRrnK1VDDtWQ/mF/3Jrq43JoP0E=
|
|
22
|
+
-----END CERTIFICATE-----
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE REQUEST-----
|
|
2
|
+
MIICrDCCAZQCAQAwZzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQ4wDAYDVQQK
|
|
3
|
+
DAVOYWlsczESMBAGA1UEAwwJbG9jYWxob3N0MScwJQYJKoZIhvcNAQkBFhhhZG1p
|
|
4
|
+
bkBwcm9qZWN0aW52aWN0YS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
|
5
|
+
AoIBAQCz+eKxg4NS6OxUrKuMb7znorFiyc202TfobMS98rXMb5N6InVaGQw35Ayd
|
|
6
|
+
UAaDxYyMh5SWQrwupiTHmNzYm59c2QLbEk/OAwmEvHNG0AGxFHPjsEpjaVS0BJZ0
|
|
7
|
+
wCsqGP+4s4+e/aebke1iw5kpNnOIoHqozgEJ/66wty6/g6+hwN5XBEA+4POzkM+y
|
|
8
|
+
QkWOqeRPfNBzvNYJJ58aHb3kKIG63okPjDsAvajzsHyYwF/6pE1nNUlyIldkrJKC
|
|
9
|
+
ADU2xrozB2WWSGmOWuaFmfaQCkdG2rEgIxAjJq9f1AihmXqLdAGUSjAUh6eppR5R
|
|
10
|
+
OSyxSB+ej2kU4LkgYbK5XgVnLlHFAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEA
|
|
11
|
+
U9LsZPK6UDQJFNCVAwDQszIE8Jt5LsNR/h7/ljp98T2BEW5+i7kPGCF+sIzkafQR
|
|
12
|
+
1NEKrwq8nAHOoS7cbzTQCtRLHgKQ5edj/dWVEzDmhf07uvq2wc9QmBjw9DIWD9Hd
|
|
13
|
+
7P4FsOHEp++4h+CupNwLaMrisggsWtVihvqpSJxWt3IzvoqWKldBfIZfR1nf2Tl+
|
|
14
|
+
2N1taAX+LHWQwzoq5xMMxmtQgabZk5kbeJ2K+NyxP3msjmREsRn0+TWzw9sTU6qu
|
|
15
|
+
9EZtiW6xje2KlvjSmRP7pvJg17GbtqCHSVWamcHqs/HE69SZhgY/iWJk7eIJhSY3
|
|
16
|
+
/b5srd0URvtlTivyQgsfUg==
|
|
17
|
+
-----END CERTIFICATE REQUEST-----
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
-----BEGIN PRIVATE KEY-----
|
|
2
|
+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCz+eKxg4NS6OxU
|
|
3
|
+
rKuMb7znorFiyc202TfobMS98rXMb5N6InVaGQw35AydUAaDxYyMh5SWQrwupiTH
|
|
4
|
+
mNzYm59c2QLbEk/OAwmEvHNG0AGxFHPjsEpjaVS0BJZ0wCsqGP+4s4+e/aebke1i
|
|
5
|
+
w5kpNnOIoHqozgEJ/66wty6/g6+hwN5XBEA+4POzkM+yQkWOqeRPfNBzvNYJJ58a
|
|
6
|
+
Hb3kKIG63okPjDsAvajzsHyYwF/6pE1nNUlyIldkrJKCADU2xrozB2WWSGmOWuaF
|
|
7
|
+
mfaQCkdG2rEgIxAjJq9f1AihmXqLdAGUSjAUh6eppR5ROSyxSB+ej2kU4LkgYbK5
|
|
8
|
+
XgVnLlHFAgMBAAECggEAJRJufyk7VkszTxfIOGPV0hLhnhs6e6uYyBALkKLbjtJW
|
|
9
|
+
2vwZFyd8rFCVxpuy09bP5iyRT0hM0gEYJ2MV7qpTr8DlxTFm7eUTQ1u8FRSInKy9
|
|
10
|
+
WGO6VvLd5zzgrwjce03t8uJNza6rJTDwaH0o4ePc9YI08euJLEGV/sGk5/8coOEr
|
|
11
|
+
sdczGdxxumLEew9vwjDbIFuuVr4YHn/qs6h8DzEg595jWBibWxqVx4JvKTAMCmeM
|
|
12
|
+
oLi251i2y3NLoKRd/+MOQ1WW9fLMiA1/cbhICqp3hGCGRv/g71bM0DVPsfmSPwGt
|
|
13
|
+
Jm+Wtv12gmRqfDw5N+hJxAIUiW1CqU9SAZDmrPV+ewKBgQD373V/fBV1x73Mhbsr
|
|
14
|
+
+4IZxmp4CbLeT2aUFMThLfTCfs7zNL4VRfHwSw6n503YNANmBqBq8bKcNQqmTnXH
|
|
15
|
+
EKvc7liSfSn0STLZtrubHkNe5t2TvUUQNOQBENsU0S8nS+ei+E0xJ6wey2TjN23F
|
|
16
|
+
0CoEbh8/xhH0hoLT3B3GcAwNtwKBgQC51IjKPdlo1jmIUjNcGz76SpcMowkWp0+s
|
|
17
|
+
qAEh0ksSCh1Pn4G+YhgoFmFcUahwkyP2CmAtHUrL+atw4b22/jHiJN/IfyhUPP31
|
|
18
|
+
0ereRpi33m2dImz6PzistyM0jPdMAKz+W2wEBmOF6Z78MgaxUZm3s0CeXGYkzWoH
|
|
19
|
+
iLQGJyMcYwKBgQDjtusTy8NqCaooziq6mqVDRxlCZqYByKtOFkU9DBhhClbIyQhM
|
|
20
|
+
QZGUQVuUmrzEdgEpE60CjDqffZfqZuWFj6pJoB95a7u8wf4SN+LW9VSrNR8NMijc
|
|
21
|
+
WbePwwt0cyv7y5tT8vnyy50qK2Tdy2rm4+mzZ/ELgb+79k7yhphSSVbIwQKBgC1u
|
|
22
|
+
LjrzP/GHXe1b2z6LUqwyDBeEzDYDlVDqicxQ8xVn756Fqlx28tzqC8dcF0feUQ5X
|
|
23
|
+
nweof566XRVtusm//0YAKc2EeMGPX673MOpCbBeXg0jFH8tWJW7kHvE7/UFRcPmG
|
|
24
|
+
NDQPs8kLQlj5ifVTs7bbVdLhV/9rUJ6i5xASBV1tAoGAAess1DjK1jnX+v6h0/OP
|
|
25
|
+
GFgg2cFB1ZarAstYHgLrLu+1Iuj9RDuTNwyiQDwT8gbz4i43o4zWE0NhQwlhJ84K
|
|
26
|
+
EY5BgS8a7sILoZjo+Mfd06bQy0AhgmYtW8mojh9/9vfg42mE2bIlSVLnbWnSkvID
|
|
27
|
+
jTFVReA7tpBS7h/Q6rW2hM8=
|
|
28
|
+
-----END PRIVATE KEY-----
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
|
2
|
+
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
|
|
30
|
+
-----END ENCRYPTED PRIVATE KEY-----
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---- BEGIN SSH2 PUBLIC KEY ----
|
|
2
|
+
Comment: "2048-bit RSA, converted by stantonwjones@darkmatter.lan from"
|
|
3
|
+
AAAAB3NzaC1yc2EAAAADAQABAAABAQDPJQsK/daFi/b+7bOSEJcKdzjvNJygX3BvMQ4HY+
|
|
4
|
+
JJaiSDyQgtwc8K85XDH0/eWyu5a6OzbadU3SkSdYP+0+uTdxfxRUCChKoASIoAaAfwB/BW
|
|
5
|
+
WOIdsuGPhJjYiLnPL4SScFdjUbJXGP5JOSQ6wgsRdqsDeQezUjF0CvR1CXoJaqRQt7p5T9
|
|
6
|
+
TlRzzuhN5Vf6BDpXBPTcNyUGKCaUwGQn2QmpXzRXrAZNb7XpzBSXdpUWm9W7U9zCFHva7J
|
|
7
|
+
XCuXsC9yMy3w1mpbL+oFBx7Wvic5FqwnATXjM7xBSqcG4tYzrISyn5pj13cIzzk9aEPRI3
|
|
8
|
+
qhV6kiA62JofiX1RkxMP+j
|
|
9
|
+
---- END SSH2 PUBLIC KEY ----
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nails_app",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "A basic nails application",
|
|
5
|
+
"main": "server.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
9
|
+
"start": "node server.js"
|
|
10
|
+
},
|
|
11
|
+
"author": "",
|
|
12
|
+
"license": "BSD",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/stantonwjones/nails-boilerplate/issues"
|
|
15
|
+
},
|
|
16
|
+
"config": {
|
|
17
|
+
"mongodbMemoryServer": {
|
|
18
|
+
"version": "latest"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import nails from "../../../../../index.js";
|
|
2
|
+
import Dog from "../models/dog.js";
|
|
3
|
+
import Owner from "../models/owner.js";
|
|
4
|
+
|
|
5
|
+
export default class DefaultJsonController extends nails.Controller {
|
|
6
|
+
json = true;
|
|
7
|
+
routes = [
|
|
8
|
+
['get', '/listowners'],
|
|
9
|
+
['get', '/listowneddogs'],
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
async listowners(params, request, response) {
|
|
13
|
+
return await Owner.findAll();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async listowneddogs(params, request, response) {
|
|
17
|
+
// await nails._dbConnector.afterInitialization();
|
|
18
|
+
// await Dog.sync({alter: true});
|
|
19
|
+
return await Dog.findAll();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export default function HomeController() {
|
|
2
|
+
this.index = function(params, request, response) {
|
|
3
|
+
console.log("HOME::INDEX");
|
|
4
|
+
response.json({
|
|
5
|
+
home_index: true
|
|
6
|
+
});
|
|
7
|
+
};
|
|
8
|
+
this.testaction = function(params, request, response) {
|
|
9
|
+
response.json({
|
|
10
|
+
home_testaction: true
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
this.test_ejs = function() {
|
|
14
|
+
};
|
|
15
|
+
/*
|
|
16
|
+
this.public_index = function(params, request, response) {
|
|
17
|
+
response.public({path: 'index.html'});
|
|
18
|
+
};
|
|
19
|
+
this.json = function(params, request, response) {
|
|
20
|
+
response.json({test: 'json'});
|
|
21
|
+
};
|
|
22
|
+
// By setting a method to asynchronous, Nails will wait for an
|
|
23
|
+
// explicit response to the client. Otherwise, it will attempt
|
|
24
|
+
// to respond with a view immediately after the action terminates.
|
|
25
|
+
this.json.async = true;
|
|
26
|
+
|
|
27
|
+
this.test_model = function(params, request, response) {
|
|
28
|
+
var u = new User();
|
|
29
|
+
u.set('created_at', (new Date()).getTime());
|
|
30
|
+
u.save();
|
|
31
|
+
response.json({new_user_id: u.id.toString()});
|
|
32
|
+
};
|
|
33
|
+
this.test_id_template = function(params, request, response) {
|
|
34
|
+
var varz = {};
|
|
35
|
+
varz.id = params.id || "no id set";
|
|
36
|
+
response.render('test_id', varz);
|
|
37
|
+
};
|
|
38
|
+
*/
|
|
39
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import nails from '../../../../../index.js';
|
|
2
|
+
import { DataTypes } from 'sequelize';
|
|
3
|
+
import Dog from './dog.js';
|
|
4
|
+
const ownerSchema = {
|
|
5
|
+
name: DataTypes.STRING,
|
|
6
|
+
};
|
|
7
|
+
class Owner extends new nails.Model("Owner", ownerSchema) {};
|
|
8
|
+
Owner.hasMany(Dog);
|
|
9
|
+
await Dog.sync();
|
|
10
|
+
export default Owner;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
I am some arbitrary text
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/* jshint esversion: 6 */
|
|
2
|
+
var React = require('react');
|
|
3
|
+
|
|
4
|
+
class TestReact extends React.Component {
|
|
5
|
+
render() {
|
|
6
|
+
return (
|
|
7
|
+
<html>
|
|
8
|
+
<head><title>react</title></head>
|
|
9
|
+
<body>react works!</body>
|
|
10
|
+
</html>
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
module.exports = TestReact;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// var nails = require('../../../index.js');
|
|
2
|
+
import nails from '../../../index.js';
|
|
3
|
+
import service_config from './config/service.js';
|
|
4
|
+
|
|
5
|
+
// See self-documented config files
|
|
6
|
+
// var service_config = require('./config/service.js');
|
|
7
|
+
// console.log("starting server")
|
|
8
|
+
(await nails( service_config )).startServer();
|
|
9
|
+
export default nails; // export nails for testing
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import * as chai from 'chai';
|
|
2
|
+
import { default as chaiHttp, request } from "chai-http";
|
|
3
|
+
// import chaiHttp from 'chai-http';
|
|
4
|
+
import { assert } from 'chai';
|
|
5
|
+
// import { WebSocket } from 'ws';
|
|
6
|
+
import WebSocket from 'ws';
|
|
7
|
+
// const WebSocket = require('ws');
|
|
8
|
+
|
|
9
|
+
var express_app;
|
|
10
|
+
// const {MongoMemoryServer} = require('mongodb-memory-server');
|
|
11
|
+
let mongod = null;
|
|
12
|
+
|
|
13
|
+
// Configure chai
|
|
14
|
+
chai.use(chaiHttp);
|
|
15
|
+
chai.should();
|
|
16
|
+
|
|
17
|
+
describe("Integration", function () {
|
|
18
|
+
before(async function () {
|
|
19
|
+
try {
|
|
20
|
+
var nails = (await import('./services/integration_sequelize/server.js')).default;
|
|
21
|
+
} catch (e) {
|
|
22
|
+
console.log("could not import server");
|
|
23
|
+
console.log(e);
|
|
24
|
+
}
|
|
25
|
+
console.log("got here");
|
|
26
|
+
express_app = nails.application;
|
|
27
|
+
return new Promise((resolve, reject) => {
|
|
28
|
+
nails.events.on("ready", () => {
|
|
29
|
+
console.log("ready was emitted!");
|
|
30
|
+
resolve();
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
describe("GET /", function () {
|
|
35
|
+
it('should return the expected JSON from index', function (done) {
|
|
36
|
+
request.execute(express_app)
|
|
37
|
+
.get('/')
|
|
38
|
+
.end((err, res) => {
|
|
39
|
+
res.should.have.status(200);
|
|
40
|
+
assert(res.text == JSON.stringify({ home_index: true }));
|
|
41
|
+
done();
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
describe("/listowners", function() {
|
|
46
|
+
it('should return an empty array if no owners', function(done) {
|
|
47
|
+
request.execute(express_app)
|
|
48
|
+
.get('/listowners')
|
|
49
|
+
.end((err, res) => {
|
|
50
|
+
res.should.have.status(200);
|
|
51
|
+
assert(JSON.parse(res.text).length == 0);
|
|
52
|
+
done();
|
|
53
|
+
});
|
|
54
|
+
})
|
|
55
|
+
})
|
|
56
|
+
describe("/listowneddogs", function() {
|
|
57
|
+
it('should return an empty array if no owned dogs', function(done) {
|
|
58
|
+
request.execute(express_app)
|
|
59
|
+
.get('/listowneddogs')
|
|
60
|
+
.end((err, res) => {
|
|
61
|
+
res.should.have.status(200);
|
|
62
|
+
assert(JSON.parse(res.text).length == 0);
|
|
63
|
+
done();
|
|
64
|
+
});
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
});
|
|
@@ -19,7 +19,7 @@ var config = {
|
|
|
19
19
|
PUBLIC_ROOT: SERVER_ROOT + '/public',
|
|
20
20
|
CONTROLLERS_ROOT: APP_ROOT + '/controllers',
|
|
21
21
|
VIEWS_ROOT: APP_ROOT + '/views',
|
|
22
|
-
|
|
22
|
+
MODELS_ROOT: APP_ROOT + '/models',
|
|
23
23
|
SERVER_ROOT: SERVER_ROOT,
|
|
24
24
|
|
|
25
25
|
ENABLE_HTTP: true,
|
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
|
-
};
|
package/lib/mongodb_connector.js
DELETED
|
@@ -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
|
-
}
|
package/lib/sqlite3_connector.js
DELETED
|
@@ -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
|
-
}
|
package/spec/model.spec.js
DELETED
|
@@ -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
|
-
}
|