nails-boilerplate 1.0.0 → 1.1.0
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/bin/lib/init.js +7 -9
- package/lib/database_connector.js +11 -0
- package/lib/mongoose_connector.js +2 -1
- package/lib/nails.js +23 -0
- package/lib/sequelize_connector.js +25 -0
- package/package.json +4 -2
- package/spec/sequelize_connector.spec.js +38 -0
- package/spec/sequelize_connector.util.js +18 -0
- package/templates/bin/start.sh +9 -0
- package/templates/config/db.js +17 -9
- package/templates/package.json +8 -6
- package/templates/server/models/user.js +15 -6
package/bin/lib/init.js
CHANGED
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
// to the path
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import fs from 'node:fs';
|
|
5
|
-
|
|
6
|
-
import wrench from 'wrench';
|
|
7
|
-
// var wrench = require('wrench');
|
|
5
|
+
import {copySync} from 'fs-extra/esm';
|
|
8
6
|
import {exec} from 'child_process';
|
|
9
7
|
// var exec = require('child_process').exec;
|
|
10
8
|
var args = process.argv.slice(2);
|
|
@@ -51,12 +49,12 @@ function createApp( name ) {
|
|
|
51
49
|
fs.writeFileSync(name + '/NAILS', '/* This marks the root of the NAILS app */');
|
|
52
50
|
fs.closeSync(fd);
|
|
53
51
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
52
|
+
copySync(path.resolve(templateRoot, './server'), name + '/server');
|
|
53
|
+
copySync(path.resolve(templateRoot, './client'), name + '/client');
|
|
54
|
+
copySync(path.resolve(templateRoot, './config'), name + '/config');
|
|
55
|
+
copySync(path.resolve(templateRoot, './common'), name + '/common');
|
|
56
|
+
copySync(path.resolve(templateRoot, './spec'), name + '/spec');
|
|
57
|
+
copySync(path.resolve(templateRoot, './bin'), name + '/bin');
|
|
60
58
|
|
|
61
59
|
checkWrites();
|
|
62
60
|
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export default class DbConnector {
|
|
2
|
+
async connect() {
|
|
3
|
+
throw 'DbConnector#connect not implemented'
|
|
4
|
+
}
|
|
5
|
+
generateModelSuperclass() {
|
|
6
|
+
throw 'GenerateModelSuperclass not implemented'
|
|
7
|
+
}
|
|
8
|
+
async afterInitialization() {
|
|
9
|
+
console.warn("DbConnector#afterInitialization not implemented");
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// const mongoose = require('mongoose');
|
|
2
2
|
import mongoose from 'mongoose';
|
|
3
|
+
import DbConnector from './database_connector.js';
|
|
3
4
|
|
|
4
|
-
class MongooseDbConnector {
|
|
5
|
+
class MongooseDbConnector extends DbConnector{
|
|
5
6
|
async connect(options) {
|
|
6
7
|
if (options.uri) {
|
|
7
8
|
this.connection = await mongoose.createConnection(options.uri/*, mongooseOptions*/).asPromise();
|
package/lib/nails.js
CHANGED
|
@@ -84,6 +84,8 @@ async function configure( app_config ) {
|
|
|
84
84
|
console.log("Generating model superclass...");
|
|
85
85
|
await DBConnector.connect(app_config.db);
|
|
86
86
|
ModelV2.setConnector(DBConnector);
|
|
87
|
+
init_models_v2(app_config.config.MODELS_ROOT);
|
|
88
|
+
DBConnector.afterInitialization();
|
|
87
89
|
} else {
|
|
88
90
|
console.log("Instantiating DBConnector...");
|
|
89
91
|
// Try to instantiate DBConnector
|
|
@@ -166,6 +168,27 @@ async function init_app_lib(superclass, abs_path) {
|
|
|
166
168
|
});
|
|
167
169
|
}
|
|
168
170
|
|
|
171
|
+
async function init_models_v2(abs_path) {
|
|
172
|
+
if (!fs.existsSync(abs_path))
|
|
173
|
+
return console.log('Cannot initialize. Path not found.', abs_path);
|
|
174
|
+
if (fs.statSync(abs_path).isFile()) {
|
|
175
|
+
console.log('attempting to import:', abs_path);
|
|
176
|
+
// We just need to import each model once so the generateSuperclass
|
|
177
|
+
// method is called at least once for each model.
|
|
178
|
+
let modelClass = (await import(abs_path)).default;
|
|
179
|
+
console.log('imported model:', modelClass.name);
|
|
180
|
+
// // Constructor function was provided
|
|
181
|
+
// if (!superclass.isPrototypeOf(subclass))
|
|
182
|
+
// return superclass.extend(subclass);
|
|
183
|
+
// ES6 Class was provided
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const directory_contents = fs.readdirSync(abs_path);
|
|
187
|
+
for (const rel_path of directory_contents) {
|
|
188
|
+
await init_models_v2(path.join(abs_path, rel_path));
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
169
192
|
// retrieves the connector object. If cannot
|
|
170
193
|
// require the module with the same name,
|
|
171
194
|
// try grabbing connector from lib
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import DbConnector from './database_connector.js';
|
|
2
|
+
import { Sequelize } from 'sequelize';
|
|
3
|
+
// const { Sequelize } = require('sequelize');
|
|
4
|
+
|
|
5
|
+
export default class SequelizeConnector extends DbConnector {
|
|
6
|
+
sequelize;
|
|
7
|
+
|
|
8
|
+
async connect(options) {
|
|
9
|
+
this.sequelize = new Sequelize(options.address);
|
|
10
|
+
try {
|
|
11
|
+
await this.sequelize.authenticate();
|
|
12
|
+
console.log('Connection has been established successfully.');
|
|
13
|
+
} catch (error) {
|
|
14
|
+
console.error('Unable to connect to the database:', error);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
generateModelSuperclass(name, options) {
|
|
19
|
+
return this.sequelize.define(name, options);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async afterInitialization() {
|
|
23
|
+
this.sequelize.sync({alter: true});
|
|
24
|
+
}
|
|
25
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nails-boilerplate",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "A node.js webserver scaffold",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -31,14 +31,16 @@
|
|
|
31
31
|
"ejs": "*",
|
|
32
32
|
"express": "*",
|
|
33
33
|
"express-ws": "*",
|
|
34
|
+
"fs-extra": "^11.3.2",
|
|
34
35
|
"mime": "*",
|
|
35
36
|
"mongodb": "^4.17.2",
|
|
36
37
|
"mongodb-memory-server": "^8.16.0",
|
|
37
38
|
"mongoose": "^6.13.0",
|
|
38
39
|
"react": "*",
|
|
39
40
|
"react-dom": "^16.13.1",
|
|
41
|
+
"sequelize": "^6.37.7",
|
|
40
42
|
"showdown": "^2.1.0",
|
|
41
|
-
"
|
|
43
|
+
"sqlite3": "^5.1.7"
|
|
42
44
|
},
|
|
43
45
|
"devDependencies": {
|
|
44
46
|
"chai": "*",
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// import SequelizeConnector from '../lib/sequelize_connector.js';
|
|
2
|
+
import assert from 'assert';
|
|
3
|
+
import Model from '../lib/model_v2.js';
|
|
4
|
+
import { DataTypes } from 'sequelize';
|
|
5
|
+
import SequelizeConnectorUtil from './sequelize_connector.util.js';
|
|
6
|
+
|
|
7
|
+
const TEST_SCHEMA = {
|
|
8
|
+
name: DataTypes.STRING,
|
|
9
|
+
favoriteColor: {
|
|
10
|
+
type: DataTypes.STRING,
|
|
11
|
+
defaultValue: 'green',
|
|
12
|
+
},
|
|
13
|
+
age: DataTypes.INTEGER,
|
|
14
|
+
cash: DataTypes.INTEGER,
|
|
15
|
+
}
|
|
16
|
+
let TestSequelizeModel = null;
|
|
17
|
+
|
|
18
|
+
describe('ModelV2 using SequelizeConnector', function() {
|
|
19
|
+
let util;
|
|
20
|
+
beforeEach(async function() {
|
|
21
|
+
util = new SequelizeConnectorUtil();
|
|
22
|
+
let connector = await util.getTestConnector();
|
|
23
|
+
Model.setConnector(connector);
|
|
24
|
+
TestSequelizeModel =
|
|
25
|
+
class TestSequelizeModel extends new Model("TestSequelizeModel", TEST_SCHEMA) {
|
|
26
|
+
};
|
|
27
|
+
await connector.sequelize.sync({ force: true });
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("Should be able to create, save, and retrieve a model", async function() {
|
|
31
|
+
const MODEL_NAME = "First test model created";
|
|
32
|
+
const testModel = TestSequelizeModel.build({name: MODEL_NAME});
|
|
33
|
+
await testModel.save();
|
|
34
|
+
const models = await TestSequelizeModel.findAll();
|
|
35
|
+
assert(models.length == 1, "Should have one model");
|
|
36
|
+
assert(models[0].name == MODEL_NAME, "Name should be consistent");
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import SequelizeConnector from '../lib/sequelize_connector.js';
|
|
2
|
+
|
|
3
|
+
class SequelizeConnectorUtil {
|
|
4
|
+
constructor() {
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
async getTestConnector() {
|
|
8
|
+
const dbConnector = new SequelizeConnector();
|
|
9
|
+
this.connection = await dbConnector.connect({address: 'sqlite::memory:'});
|
|
10
|
+
debugger;
|
|
11
|
+
return dbConnector;
|
|
12
|
+
}
|
|
13
|
+
async cleanup() {
|
|
14
|
+
debugger;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default SequelizeConnectorUtil;
|
package/templates/config/db.js
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
export default {
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* For the sqlite3 connector. Unless a filename is defined, an in-memory
|
|
4
|
+
* database is used. In-memory databases are not persisted, and will be lost
|
|
5
|
+
* when the server is restarted.
|
|
6
|
+
*/
|
|
7
|
+
// connector: 'sqlite3_connector.js',
|
|
8
|
+
// filename: ':memory:'
|
|
9
|
+
|
|
10
|
+
/** Mongoose Connector */
|
|
3
11
|
// connector: 'mongoose_connector.js',
|
|
4
|
-
|
|
5
|
-
//
|
|
6
|
-
//port: '27017',
|
|
12
|
+
// url: 'mongodb://localhost',
|
|
13
|
+
// port: '27017',
|
|
7
14
|
|
|
8
|
-
|
|
15
|
+
/** Mongoose Memory Server Connector */
|
|
16
|
+
// connector: 'mongoose_mem_connector.js',
|
|
17
|
+
// database: 'development',
|
|
9
18
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
//filename: ':memory:'
|
|
19
|
+
/** Sequelize Connector */
|
|
20
|
+
connector: 'sequelize_connector.js',
|
|
21
|
+
address: 'sqlite::memory:',
|
|
14
22
|
}
|
package/templates/package.json
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
"description": "A basic nails application",
|
|
5
5
|
"main": "server.js",
|
|
6
6
|
"type": "module",
|
|
7
|
+
"bin": "./bin/start.sh",
|
|
7
8
|
"scripts": {
|
|
8
9
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
9
10
|
"start": "vite build & node bin/server.js",
|
|
@@ -23,19 +24,20 @@
|
|
|
23
24
|
},
|
|
24
25
|
"dependencies": {
|
|
25
26
|
"nails-boilerplate": ">=0.1.0",
|
|
27
|
+
"vite": "^6.3.5",
|
|
28
|
+
"@vitejs/plugin-legacy": "^6.1.1",
|
|
29
|
+
"@vitejs/plugin-react": "^4.7.0",
|
|
26
30
|
"react": "^19.1.0",
|
|
27
31
|
"react-dom": "^19.1.0",
|
|
28
|
-
"react-router-dom": "^7.7.0"
|
|
32
|
+
"react-router-dom": "^7.7.0",
|
|
33
|
+
"sequelize": "^6.37.7",
|
|
34
|
+
"@mui/material": "^7.3.1",
|
|
35
|
+
"@mui/icons-material": "^7.3.1"
|
|
29
36
|
},
|
|
30
37
|
"devDependencies": {
|
|
31
|
-
"vite": "^6.3.5",
|
|
32
38
|
"vitest": "^3.2.4",
|
|
33
|
-
"@vitejs/plugin-legacy": "^6.1.1",
|
|
34
|
-
"@vitejs/plugin-react": "^4.7.0",
|
|
35
39
|
"@emotion/react": "^11.14.0",
|
|
36
40
|
"@emotion/styled": "^11.14.1",
|
|
37
|
-
"@mui/material": "^7.3.1",
|
|
38
|
-
"@mui/icons-material": "^7.3.1",
|
|
39
41
|
"@mui/types": "^7.4.5"
|
|
40
42
|
}
|
|
41
43
|
}
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import nails from "nails-boilerplate";
|
|
2
|
+
import { DataTypes } from 'sequelize';
|
|
2
3
|
const Model = nails.Model;
|
|
3
4
|
|
|
4
|
-
const
|
|
5
|
-
name:
|
|
6
|
-
verified:
|
|
7
|
-
email:
|
|
8
|
-
}
|
|
9
|
-
export default class User extends new Model("User",
|
|
5
|
+
const sequelizeUserSchema = {
|
|
6
|
+
name: DataTypes.STRING,
|
|
7
|
+
verified: DataTypes.BOOLEAN,
|
|
8
|
+
email: DataTypes.STRING
|
|
9
|
+
}
|
|
10
|
+
export default class User extends new Model("User", sequelizeUserSchema) {};
|
|
11
|
+
|
|
12
|
+
/** If using a mongoose connector */
|
|
13
|
+
// const mongooseUserSchema = {
|
|
14
|
+
// name: String,
|
|
15
|
+
// verified: Boolean,
|
|
16
|
+
// email: String
|
|
17
|
+
// };
|
|
18
|
+
// export default class User extends new Model("User", {schema: mongooseUserSchema}) {};
|