fable 3.0.32 → 3.0.33
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/.config/retold-harness/MySQL-Laden-Entry.sh +17 -0
- package/.config/retold-harness/MySQL-Security.sql +5 -0
- package/.config/retold-harness/bookstore-api-endpoint-exercises.paw +0 -0
- package/.config/retold-harness/bookstore-configuration.json +28 -0
- package/.config/retold-harness/bookstore-import-books-run.js +1 -0
- package/.config/retold-harness/bookstore-import-books.js +214 -0
- package/.config/retold-harness/bookstore-serve-meadow-endpoint-apis-IPC.js +137 -0
- package/.config/retold-harness/bookstore-serve-meadow-endpoint-apis.js +128 -0
- package/.config/retold-harness/data/books.csv +10001 -0
- package/.config/retold-harness/model/ddl/BookStore.ddl +66 -0
- package/.config/retold-harness/model/generated_diagram/README.md +1 -0
- package/.config/retold-harness/model/generated_diagram/Stricture_Output.dot +13 -0
- package/.config/retold-harness/model/generated_diagram/Stricture_Output.png +0 -0
- package/.config/retold-harness/model/generated_documentation/Dictionary.md +18 -0
- package/.config/retold-harness/model/generated_documentation/Model-Author.md +20 -0
- package/.config/retold-harness/model/generated_documentation/Model-Book.md +26 -0
- package/.config/retold-harness/model/generated_documentation/Model-BookAuthorJoin.md +14 -0
- package/.config/retold-harness/model/generated_documentation/Model-BookPrice.md +25 -0
- package/.config/retold-harness/model/generated_documentation/Model-Review.md +22 -0
- package/.config/retold-harness/model/generated_documentation/ModelChangeTracking.md +17 -0
- package/.config/retold-harness/model/generated_documentation/README.md +1 -0
- package/.config/retold-harness/model/json_schema/BookStore-Extended.json +915 -0
- package/.config/retold-harness/model/json_schema/BookStore-PICT.json +1 -0
- package/.config/retold-harness/model/json_schema/BookStore.json +280 -0
- package/.config/retold-harness/model/json_schema/README.md +1 -0
- package/.config/retold-harness/model/manual_scripts/DropTables.sql +5 -0
- package/.config/retold-harness/model/manual_scripts/README.md +2 -0
- package/.config/retold-harness/model/meadow_schema/BookStore-MeadowSchema-Author.json +220 -0
- package/.config/retold-harness/model/meadow_schema/BookStore-MeadowSchema-Book.json +268 -0
- package/.config/retold-harness/model/meadow_schema/BookStore-MeadowSchema-BookAuthorJoin.json +172 -0
- package/.config/retold-harness/model/meadow_schema/BookStore-MeadowSchema-BookPrice.json +260 -0
- package/.config/retold-harness/model/meadow_schema/BookStore-MeadowSchema-Review.json +236 -0
- package/.config/retold-harness/model/meadow_schema/README.md +1 -0
- package/.config/retold-harness/model/sql_create/BookStore-CreateDatabase.mysql.sql +116 -0
- package/.config/retold-harness/model/sql_create/README.md +1 -0
- package/.config/retold-harness/test_old/Tests.js +3243 -0
- package/.config/retold-harness/test_old/untitled.js +88 -0
- package/Dockerfile_LUXURYCode +18 -0
- package/README.md +1 -1
- package/dist/fable.compatible.js +0 -10
- package/dist/fable.compatible.min.js +2 -78
- package/dist/fable.compatible.min.js.map +1 -1
- package/dist/fable.js +0 -10
- package/dist/fable.min.js +2 -70
- package/dist/fable.min.js.map +1 -1
- package/package.json +5 -5
- package/source/Fable-ServiceManager.js +0 -1
- package/source/Fable.js +0 -1
- package/source/services/Fable-Service-DataFormat.js +0 -1
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
trap 'kill -TERM $PID' TERM INT
|
|
4
|
+
|
|
5
|
+
/usr/bin/entrypoint.sh --bind-addr "0.0.0.0:8080" . &
|
|
6
|
+
|
|
7
|
+
PID=$!
|
|
8
|
+
|
|
9
|
+
sleep 2
|
|
10
|
+
|
|
11
|
+
sudo service mariadb restart
|
|
12
|
+
|
|
13
|
+
wait $PID
|
|
14
|
+
trap - TERM INT
|
|
15
|
+
wait $PID
|
|
16
|
+
EXIT_STATUS=$?
|
|
17
|
+
echo "Service exited with status ${EXIT_STATUS}"
|
|
Binary file
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Product": "MeadowEndpointsTestBookStore",
|
|
3
|
+
"ProductVersion": "1.0.0",
|
|
4
|
+
|
|
5
|
+
"UUID":
|
|
6
|
+
{
|
|
7
|
+
"DataCenter": 0,
|
|
8
|
+
"Worker": 0
|
|
9
|
+
},
|
|
10
|
+
"LogStreams":
|
|
11
|
+
[
|
|
12
|
+
{
|
|
13
|
+
"streamtype": "console"
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
|
|
17
|
+
"APIServerPort": 8086,
|
|
18
|
+
|
|
19
|
+
"MySQL":
|
|
20
|
+
{
|
|
21
|
+
"Server": "127.0.0.1",
|
|
22
|
+
"Port": 3306,
|
|
23
|
+
"User": "root",
|
|
24
|
+
"Password": "123456789",
|
|
25
|
+
"Database": "bookstore",
|
|
26
|
+
"ConnectionPoolLimit": 20
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
let tmpRun = require('./bookstore-import-books.js')();
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Import Books directly from CSV to SQL.
|
|
3
|
+
|
|
4
|
+
An example of how to use the Meadow DALs directly.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* @author <steven@velozo.com>
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// Server Settings
|
|
11
|
+
const _Settings = require('./bookstore-configuration.json');
|
|
12
|
+
// Fable is logging and settings
|
|
13
|
+
const libFable = require('fable');
|
|
14
|
+
// Official MySQL Client
|
|
15
|
+
const libMySQL = require('mysql2');
|
|
16
|
+
// Meadow is the DAL
|
|
17
|
+
const libMeadow = require('meadow');
|
|
18
|
+
|
|
19
|
+
const libAsync = require('async');
|
|
20
|
+
|
|
21
|
+
let _Fable = libFable.new(_Settings);
|
|
22
|
+
let _Meadow = libMeadow.new(_Fable);
|
|
23
|
+
|
|
24
|
+
_Fable.log.info("Application is starting up...");
|
|
25
|
+
|
|
26
|
+
_Fable.log.info("...Creating SQL Connection pools at "+_Fable.settings.MySQL.Server+"...");
|
|
27
|
+
// Setup SQL Connection Pool
|
|
28
|
+
_Fable.MeadowMySQLConnectionPool = libMySQL.createPool
|
|
29
|
+
(
|
|
30
|
+
{
|
|
31
|
+
connectionLimit: _Fable.settings.MySQL.ConnectionPoolLimit,
|
|
32
|
+
host: _Fable.settings.MySQL.Server,
|
|
33
|
+
port: _Fable.settings.MySQL.Port,
|
|
34
|
+
user: _Fable.settings.MySQL.User,
|
|
35
|
+
password: _Fable.settings.MySQL.Password,
|
|
36
|
+
database: _Fable.settings.MySQL.Database,
|
|
37
|
+
namedPlaceholders: true
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
// Create DAL objects
|
|
42
|
+
let _DAL = {};
|
|
43
|
+
const _BookStoreModel = require (__dirname+'/model/json_schema/BookStore-Extended.json');
|
|
44
|
+
const _BookStoreTableList = Object.keys(_BookStoreModel.Tables);
|
|
45
|
+
_Fable.log.info(`...Creating ${_BookStoreTableList.length} DAL entries...`);
|
|
46
|
+
for (let i = 0; i < _BookStoreTableList.length; i++)
|
|
47
|
+
{
|
|
48
|
+
let tmpDALEntityName = _BookStoreTableList[i];
|
|
49
|
+
_Fable.log.info(` -> Creating the ${tmpDALEntityName} DAL...`);
|
|
50
|
+
_DAL[tmpDALEntityName] = _Meadow.loadFromPackage(__dirname+'/model/meadow_schema/BookStore-MeadowSchema-'+tmpDALEntityName+'.json');
|
|
51
|
+
_DAL[tmpDALEntityName].setProvider('MySQL');
|
|
52
|
+
_DAL[tmpDALEntityName].setIDUser(99999);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const libPapa = require('papaparse');
|
|
56
|
+
const libFS = require('fs');
|
|
57
|
+
|
|
58
|
+
const _BookData = libFS.readFileSync(`${__dirname}/data/books.csv`, 'utf8');
|
|
59
|
+
|
|
60
|
+
let tmpBookMap = {};
|
|
61
|
+
let tmpAuthorMap = {};
|
|
62
|
+
|
|
63
|
+
let fImportBooks = (fCallback) =>
|
|
64
|
+
{
|
|
65
|
+
console.log('Import operation executing...');
|
|
66
|
+
let tmpCallback = (typeof(fCallback) == 'function') ? fCallback : ()=>{};
|
|
67
|
+
|
|
68
|
+
libPapa.parse(_BookData,
|
|
69
|
+
{
|
|
70
|
+
delimiter: ",",
|
|
71
|
+
header: true,
|
|
72
|
+
complete:
|
|
73
|
+
(pResults) =>
|
|
74
|
+
{
|
|
75
|
+
libAsync.waterfall([
|
|
76
|
+
(fStageComplete) =>
|
|
77
|
+
{
|
|
78
|
+
// Enumerate and insert each book
|
|
79
|
+
libAsync.eachLimit(pResults.data, 10,
|
|
80
|
+
(pBookDataRow, fCallback) =>
|
|
81
|
+
{
|
|
82
|
+
let tmpRecordToCreate = (
|
|
83
|
+
{
|
|
84
|
+
Title: pBookDataRow.original_title,
|
|
85
|
+
PublicationYear: isNaN(parseInt(pBookDataRow.original_publication_year, 10)) ? 0 : parseInt(pBookDataRow.original_publication_year, 10),
|
|
86
|
+
ISBN: pBookDataRow.isbn,
|
|
87
|
+
Type: 'Paper',
|
|
88
|
+
Genre: 'UNKNOWN',
|
|
89
|
+
Language: pBookDataRow.language_code,
|
|
90
|
+
ImageURL: pBookDataRow.image_url
|
|
91
|
+
});
|
|
92
|
+
let tmpQuery = _DAL.Book.query;
|
|
93
|
+
//tmpQuery.setLogLevel(5);
|
|
94
|
+
tmpQuery.addRecord(tmpRecordToCreate);
|
|
95
|
+
_DAL.Book.doCreate(tmpQuery,
|
|
96
|
+
(pError, pQuery, pQueryRead, pRecord)=>
|
|
97
|
+
{
|
|
98
|
+
// Add it to the book map
|
|
99
|
+
if (!pError)
|
|
100
|
+
{
|
|
101
|
+
tmpBookMap[pBookDataRow.id] = pRecord.IDBook;
|
|
102
|
+
//_Fable.log.info('Imported book ID '+pRecord.IDBook+' title ['+pRecord.Title+']');
|
|
103
|
+
}
|
|
104
|
+
fCallback(pError);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
},
|
|
108
|
+
(pError)=>
|
|
109
|
+
{
|
|
110
|
+
_Fable.log.info('...Book Import operation complete!');
|
|
111
|
+
fStageComplete()
|
|
112
|
+
});
|
|
113
|
+
},
|
|
114
|
+
(fStageComplete) =>
|
|
115
|
+
{
|
|
116
|
+
// Enumerate and insert each author
|
|
117
|
+
libAsync.eachLimit(pResults.data, 10,
|
|
118
|
+
(pBookDataRow, fCallback) =>
|
|
119
|
+
{
|
|
120
|
+
if (!pBookDataRow.hasOwnProperty('authors'))
|
|
121
|
+
return fCallback();
|
|
122
|
+
|
|
123
|
+
let tmpAuthorsToCreate = pBookDataRow.authors.split(',');
|
|
124
|
+
|
|
125
|
+
libAsync.eachLimit(tmpAuthorsToCreate, 1,
|
|
126
|
+
(pAuthor, fAuthorInsertCallback)=>
|
|
127
|
+
{
|
|
128
|
+
if (tmpAuthorMap.hasOwnProperty(pAuthor))
|
|
129
|
+
{
|
|
130
|
+
return fAuthorInsertCallback();
|
|
131
|
+
}
|
|
132
|
+
else
|
|
133
|
+
{
|
|
134
|
+
tmpAuthorMap[pAuthor] = false;
|
|
135
|
+
}
|
|
136
|
+
let tmpRecordToCreate = (
|
|
137
|
+
{
|
|
138
|
+
Name: pAuthor
|
|
139
|
+
});
|
|
140
|
+
let tmpQuery = _DAL.Author.query.addRecord(tmpRecordToCreate);
|
|
141
|
+
_DAL.Author.doCreate(tmpQuery,
|
|
142
|
+
(pError, pQuery, pQueryRead, pRecord)=>
|
|
143
|
+
{
|
|
144
|
+
if (!pError)
|
|
145
|
+
{
|
|
146
|
+
tmpAuthorMap[pRecord.Name] = pRecord.IDAuthor;
|
|
147
|
+
//_Fable.log.info('Imported Author ID '+pRecord.IDAuthor+' named ['+pRecord.Name+']');
|
|
148
|
+
}
|
|
149
|
+
return fAuthorInsertCallback(pError);
|
|
150
|
+
});
|
|
151
|
+
},
|
|
152
|
+
(pError)=>
|
|
153
|
+
{
|
|
154
|
+
return fCallback(pError);
|
|
155
|
+
});
|
|
156
|
+
},
|
|
157
|
+
(pError)=>
|
|
158
|
+
{
|
|
159
|
+
_Fable.log.info('...Author Import operation complete!');
|
|
160
|
+
fStageComplete();
|
|
161
|
+
});
|
|
162
|
+
},
|
|
163
|
+
(fStageComplete) =>
|
|
164
|
+
{
|
|
165
|
+
// Create Book->Author joins
|
|
166
|
+
libAsync.eachLimit(pResults.data, 10,
|
|
167
|
+
(pBookDataRow, fCallback) =>
|
|
168
|
+
{
|
|
169
|
+
if (!pBookDataRow.hasOwnProperty('authors'))
|
|
170
|
+
return fCallback();
|
|
171
|
+
|
|
172
|
+
let tmpAuthorJoinsToCreate = pBookDataRow.authors.split(',');
|
|
173
|
+
|
|
174
|
+
libAsync.eachLimit(tmpAuthorJoinsToCreate, 1,
|
|
175
|
+
(pAuthor, fAuthorJoinInsertCallback)=>
|
|
176
|
+
{
|
|
177
|
+
let tmpRecordToCreate = (
|
|
178
|
+
{
|
|
179
|
+
IDBook: tmpBookMap[pBookDataRow.id],
|
|
180
|
+
IDAuthor: tmpAuthorMap[pAuthor]
|
|
181
|
+
});
|
|
182
|
+
let tmpQuery = _DAL.BookAuthorJoin.query.addRecord(tmpRecordToCreate);
|
|
183
|
+
_DAL.BookAuthorJoin.doCreate(tmpQuery,
|
|
184
|
+
(pError, pQuery, pQueryRead, pRecord)=>
|
|
185
|
+
{
|
|
186
|
+
if (!pError)
|
|
187
|
+
{
|
|
188
|
+
//_Fable.log.info(`Joined author ${pAuthor} ID ${pRecord.IDAuthor} to book ID ${pRecord.IDBook}`);
|
|
189
|
+
}
|
|
190
|
+
return fAuthorJoinInsertCallback(pError);
|
|
191
|
+
});
|
|
192
|
+
},
|
|
193
|
+
(pError)=>
|
|
194
|
+
{
|
|
195
|
+
return fCallback(pError);
|
|
196
|
+
});
|
|
197
|
+
},
|
|
198
|
+
(pError)=>
|
|
199
|
+
{
|
|
200
|
+
_Fable.log.info('...Join Import operation complete!');
|
|
201
|
+
return fStageComplete(pError);
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
],
|
|
205
|
+
(pError)=>
|
|
206
|
+
{
|
|
207
|
+
_Fable.log.info('Full import operation has completed!')
|
|
208
|
+
tmpCallback(pError);
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
module.exports = fImportBooks;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/*
|
|
2
|
+
An example of Meadow Endpoints, Fable and Orator
|
|
3
|
+
*/
|
|
4
|
+
const libWhyMe = require('why-is-node-running');
|
|
5
|
+
/**
|
|
6
|
+
* @author <steven@velozo.com>
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Server Settings
|
|
10
|
+
const _Settings = require('./bookstore-configuration.json');
|
|
11
|
+
// Fable is logging and settings
|
|
12
|
+
const libFable = require('fable');
|
|
13
|
+
// Orator is the web server
|
|
14
|
+
const libOrator = require('orator');
|
|
15
|
+
// Official MySQL Client
|
|
16
|
+
const libMySQL = require('mysql2');
|
|
17
|
+
// Meadow is the DAL
|
|
18
|
+
const libMeadow = require('meadow');
|
|
19
|
+
// Meadow-endpoints maps the DAL to restify endpoints automagically
|
|
20
|
+
const libMeadowEndpoints = require('../source/Meadow-Endpoints.js');
|
|
21
|
+
|
|
22
|
+
let _Fable = new libFable(_Settings);
|
|
23
|
+
let _Orator = new libOrator(_Fable);
|
|
24
|
+
|
|
25
|
+
let fStartServiceServer = (fInitializeCallback) =>
|
|
26
|
+
{
|
|
27
|
+
_Orator.initializeServiceServer((pError) =>
|
|
28
|
+
{
|
|
29
|
+
let _Meadow = libMeadow.new(_Fable);
|
|
30
|
+
|
|
31
|
+
_Fable.log.info("Application is starting up...");
|
|
32
|
+
|
|
33
|
+
_Fable.log.info("...Creating SQL Connection pools at "+_Fable.settings.MySQL.Server+"...");
|
|
34
|
+
_Fable.MeadowMySQLConnectionPool = libMySQL.createPool
|
|
35
|
+
(
|
|
36
|
+
{
|
|
37
|
+
connectionLimit: _Fable.settings.MySQL.ConnectionPoolLimit,
|
|
38
|
+
host: _Fable.settings.MySQL.Server,
|
|
39
|
+
port: _Fable.settings.MySQL.Port,
|
|
40
|
+
user: _Fable.settings.MySQL.User,
|
|
41
|
+
password: _Fable.settings.MySQL.Password,
|
|
42
|
+
database: _Fable.settings.MySQL.Database,
|
|
43
|
+
namedPlaceholders: true
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
// Create DAL objects for each table in the schema
|
|
48
|
+
let _DAL = {};
|
|
49
|
+
let _MeadowEndpoints = {};
|
|
50
|
+
|
|
51
|
+
// 1. Load full compiled schema of the model from stricture
|
|
52
|
+
_Fable.log.info(`...Loading stricture schemas...`);
|
|
53
|
+
const _BookStoreModel = require (__dirname+'/model/json_schema/BookStore-Extended.json');
|
|
54
|
+
|
|
55
|
+
// 2. Extract an array of each table in the schema
|
|
56
|
+
const _BookStoreTableList = Object.keys(_BookStoreModel.Tables);
|
|
57
|
+
|
|
58
|
+
// 3. Enumerate each entry in the compiled model and load a DAL for that table
|
|
59
|
+
_Fable.log.info(`...Creating ${_BookStoreTableList.length} DAL entries...`);
|
|
60
|
+
for (let i = 0; i < _BookStoreTableList.length; i++)
|
|
61
|
+
{
|
|
62
|
+
let tmpDALEntityName = _BookStoreTableList[i];
|
|
63
|
+
_Fable.log.info(` -> Creating the ${tmpDALEntityName} DAL...`);
|
|
64
|
+
// 4. Create the DAL for each entry (e.g. it would be at _DAL.Book or _DAL.Author)
|
|
65
|
+
_DAL[tmpDALEntityName] = _Meadow.loadFromPackage(__dirname+'/model/meadow_schema/BookStore-MeadowSchema-'+tmpDALEntityName+'.json');
|
|
66
|
+
// 5. Tell this DAL object to use MySQL
|
|
67
|
+
_DAL[tmpDALEntityName].setProvider('MySQL');
|
|
68
|
+
// 6. Set the User ID to 10 just for fun
|
|
69
|
+
_DAL[tmpDALEntityName].setIDUser(1);
|
|
70
|
+
// 7. Create a Meadow Endpoints class for this DAL
|
|
71
|
+
_MeadowEndpoints[tmpDALEntityName] = libMeadowEndpoints.new(_DAL[tmpDALEntityName]);
|
|
72
|
+
// 8. Expose the meadow endpoints on Orator
|
|
73
|
+
_MeadowEndpoints[tmpDALEntityName].connectRoutes(_Orator.webServer);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// 100. Add a post processing hook to the Book DAL on single reads
|
|
77
|
+
/*
|
|
78
|
+
This post processing step will look for all book author joins then
|
|
79
|
+
load all appropriate authors and stuff them in the book record before
|
|
80
|
+
returning it.
|
|
81
|
+
*/
|
|
82
|
+
_MeadowEndpoints.Book.controller.BehaviorInjection.setBehavior('Read-PostOperation',
|
|
83
|
+
(pRequest, pRequestState, fComplete) =>
|
|
84
|
+
{
|
|
85
|
+
// Get the join records
|
|
86
|
+
_DAL.BookAuthorJoin.doReads(_DAL.BookAuthorJoin.query.addFilter('IDBook', pRequestState.Record.IDBook),
|
|
87
|
+
(pJoinReadError, pJoinReadQuery, pJoinRecords)=>
|
|
88
|
+
{
|
|
89
|
+
let tmpAuthorList = [];
|
|
90
|
+
for (let j = 0; j < pJoinRecords.length; j++)
|
|
91
|
+
{
|
|
92
|
+
tmpAuthorList.push(pJoinRecords[j].IDAuthor);
|
|
93
|
+
}
|
|
94
|
+
if (tmpAuthorList.length < 1)
|
|
95
|
+
{
|
|
96
|
+
pRequestState.Record.Authors = [];
|
|
97
|
+
return fComplete();
|
|
98
|
+
}
|
|
99
|
+
else
|
|
100
|
+
{
|
|
101
|
+
_DAL.Author.doReads(_DAL.Author.query.addFilter('IDAuthor', tmpAuthorList, 'IN'),
|
|
102
|
+
(pReadsError, pReadsQuery, pAuthors)=>
|
|
103
|
+
{
|
|
104
|
+
pRequestState.Record.Authors = pAuthors;
|
|
105
|
+
return fComplete();
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Static site mapping
|
|
112
|
+
_Orator.log.info("...Mapping static route for web site...");
|
|
113
|
+
|
|
114
|
+
//_Orator.addStaticRoute(__dirname+'/../web/');
|
|
115
|
+
|
|
116
|
+
// Start the web server (ctrl+c to end it)
|
|
117
|
+
_Orator.startWebServer(
|
|
118
|
+
(pError) =>
|
|
119
|
+
{
|
|
120
|
+
// Now do a GET!
|
|
121
|
+
let tmpURI = `/1.0/Book/1`;
|
|
122
|
+
_Orator.invoke('GET', tmpURI, null,
|
|
123
|
+
(pError, pResponseData) =>
|
|
124
|
+
{
|
|
125
|
+
_Orator.log.info(`Response to [${tmpURI}] came back from IPC resulting in [${pResponseData}]!`);
|
|
126
|
+
_Fable.MeadowMySQLConnectionPool.end();
|
|
127
|
+
libWhyMe();
|
|
128
|
+
return true;
|
|
129
|
+
});
|
|
130
|
+
fInitializeCallback(pError);
|
|
131
|
+
}
|
|
132
|
+
);
|
|
133
|
+
});
|
|
134
|
+
return _Orator;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
module.exports = fStartServiceServer;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/*
|
|
2
|
+
An example of Meadow Endpoints, Fable and Orator
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @author <steven@velozo.com>
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Server Settings
|
|
10
|
+
const _Settings = require('./bookstore-configuration.json');
|
|
11
|
+
// Fable is logging and settings
|
|
12
|
+
const libFable = require('fable');
|
|
13
|
+
// Orator is the web server
|
|
14
|
+
const libOrator = require('orator');
|
|
15
|
+
const libOratorServiceServerRestify = require('orator-serviceserver-restify');
|
|
16
|
+
// Official MySQL Client
|
|
17
|
+
const libMySQL = require('mysql2');
|
|
18
|
+
// Meadow is the DAL
|
|
19
|
+
const libMeadow = require('meadow');
|
|
20
|
+
// Meadow-endpoints maps the DAL to restify endpoints automagically
|
|
21
|
+
const libMeadowEndpoints = require('../source/Meadow-Endpoints.js');
|
|
22
|
+
|
|
23
|
+
let _Fable = new libFable(_Settings);
|
|
24
|
+
let _Orator = new libOrator(_Fable, libOratorServiceServerRestify);
|
|
25
|
+
|
|
26
|
+
let fStartServiceServer = (fInitializeCallback) =>
|
|
27
|
+
{
|
|
28
|
+
_Orator.initializeServiceServer(() =>
|
|
29
|
+
{
|
|
30
|
+
let _Meadow = libMeadow.new(_Fable);
|
|
31
|
+
|
|
32
|
+
_Fable.log.info("Application is starting up...");
|
|
33
|
+
|
|
34
|
+
_Fable.log.info("...Creating SQL Connection pools at "+_Fable.settings.MySQL.Server+"...");
|
|
35
|
+
_Fable.MeadowMySQLConnectionPool = libMySQL.createPool
|
|
36
|
+
(
|
|
37
|
+
{
|
|
38
|
+
connectionLimit: _Fable.settings.MySQL.ConnectionPoolLimit,
|
|
39
|
+
host: _Fable.settings.MySQL.Server,
|
|
40
|
+
port: _Fable.settings.MySQL.Port,
|
|
41
|
+
user: _Fable.settings.MySQL.User,
|
|
42
|
+
password: _Fable.settings.MySQL.Password,
|
|
43
|
+
database: _Fable.settings.MySQL.Database,
|
|
44
|
+
namedPlaceholders: true
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
// Create DAL objects for each table in the schema
|
|
49
|
+
let _DAL = {};
|
|
50
|
+
let _MeadowEndpoints = {};
|
|
51
|
+
|
|
52
|
+
// 1. Load full compiled schema of the model from stricture
|
|
53
|
+
_Fable.log.info(`...Loading stricture schemas...`);
|
|
54
|
+
const _BookStoreModel = require (__dirname+'/model/json_schema/BookStore-Extended.json');
|
|
55
|
+
|
|
56
|
+
// 2. Extract an array of each table in the schema
|
|
57
|
+
const _BookStoreTableList = Object.keys(_BookStoreModel.Tables);
|
|
58
|
+
|
|
59
|
+
// 3. Enumerate each entry in the compiled model and load a DAL for that table
|
|
60
|
+
_Fable.log.info(`...Creating ${_BookStoreTableList.length} DAL entries...`);
|
|
61
|
+
for (let i = 0; i < _BookStoreTableList.length; i++)
|
|
62
|
+
{
|
|
63
|
+
let tmpDALEntityName = _BookStoreTableList[i];
|
|
64
|
+
_Fable.log.info(` -> Creating the ${tmpDALEntityName} DAL...`);
|
|
65
|
+
// 4. Create the DAL for each entry (e.g. it would be at _DAL.Book or _DAL.Author)
|
|
66
|
+
_DAL[tmpDALEntityName] = _Meadow.loadFromPackage(__dirname+'/model/meadow_schema/BookStore-MeadowSchema-'+tmpDALEntityName+'.json');
|
|
67
|
+
// 5. Tell this DAL object to use MySQL
|
|
68
|
+
_DAL[tmpDALEntityName].setProvider('MySQL');
|
|
69
|
+
// 6. Set the User ID to 10 just for fun
|
|
70
|
+
_DAL[tmpDALEntityName].setIDUser(1);
|
|
71
|
+
// 7. Create a Meadow Endpoints class for this DAL
|
|
72
|
+
_MeadowEndpoints[tmpDALEntityName] = libMeadowEndpoints.new(_DAL[tmpDALEntityName]);
|
|
73
|
+
// 8. Expose the meadow endpoints on Orator
|
|
74
|
+
_MeadowEndpoints[tmpDALEntityName].connectRoutes(_Orator.webServer);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// 100. Add a post processing hook to the Book DAL on single reads
|
|
78
|
+
/*
|
|
79
|
+
This post processing step will look for all book author joins then
|
|
80
|
+
load all appropriate authors and stuff them in the book record before
|
|
81
|
+
returning it.
|
|
82
|
+
*/
|
|
83
|
+
_MeadowEndpoints.Book.controller.BehaviorInjection.setBehavior('Read-PostOperation',
|
|
84
|
+
(pRequest, pRequestState, fComplete) =>
|
|
85
|
+
{
|
|
86
|
+
// Get the join records
|
|
87
|
+
_DAL.BookAuthorJoin.doReads(_DAL.BookAuthorJoin.query.addFilter('IDBook', pRequestState.Record.IDBook),
|
|
88
|
+
(pJoinReadError, pJoinReadQuery, pJoinRecords)=>
|
|
89
|
+
{
|
|
90
|
+
let tmpAuthorList = [];
|
|
91
|
+
for (let j = 0; j < pJoinRecords.length; j++)
|
|
92
|
+
{
|
|
93
|
+
tmpAuthorList.push(pJoinRecords[j].IDAuthor);
|
|
94
|
+
}
|
|
95
|
+
if (tmpAuthorList.length < 1)
|
|
96
|
+
{
|
|
97
|
+
pRequestState.Record.Authors = [];
|
|
98
|
+
return fComplete();
|
|
99
|
+
}
|
|
100
|
+
else
|
|
101
|
+
{
|
|
102
|
+
_DAL.Author.doReads(_DAL.Author.query.addFilter('IDAuthor', tmpAuthorList, 'IN'),
|
|
103
|
+
(pReadsError, pReadsQuery, pAuthors)=>
|
|
104
|
+
{
|
|
105
|
+
pRequestState.Record.Authors = pAuthors;
|
|
106
|
+
return fComplete();
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Static site mapping
|
|
113
|
+
_Orator.log.info("...Mapping static route for web site...");
|
|
114
|
+
|
|
115
|
+
//_Orator.addStaticRoute(__dirname+'/../web/');
|
|
116
|
+
|
|
117
|
+
// Start the web server (ctrl+c to end it)
|
|
118
|
+
_Orator.startWebServer(
|
|
119
|
+
(pError) =>
|
|
120
|
+
{
|
|
121
|
+
fInitializeCallback(pError);
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
});
|
|
125
|
+
return _Orator;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
module.exports = fStartServiceServer;
|