retold-data-service 1.0.2 → 1.0.4
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/configstore/update-notifier-npm-check-updates.json +1 -1
- package/.config/configstore/update-notifier-npm.json +7 -1
- package/.config/vscode-sqltools/runningInfo.json +13 -0
- package/.vscode/launch.json +24 -0
- package/.vscode/settings.json +17 -0
- package/Dockerfile_LUXURYCode +94 -0
- package/README.md +21 -11
- package/debug/Harness.js +52 -2
- package/debug/bookstore-configuration.json +29 -0
- package/debug/data/books.csv +10001 -0
- package/debug/model/bookstore-api-endpoint-exercises.paw +0 -0
- package/debug/model/manual_scripts/MySQL-Laden-Entry.sh +17 -0
- package/debug/model/manual_scripts/MySQL-Security.sql +5 -0
- package/debug/model/manual_scripts/my.cnf +4 -0
- package/debug/model/sql_create/BookStore-CreateAndPopulateTables.sql +194 -0
- package/package.json +58 -41
- package/source/Retold-Data-Service.js +152 -288
- package/test/RetoldDataService_tests.js +20 -37
- package/test/model/fable-configuration.json +16 -0
- package/test/model/meadow/README.md +1 -0
- package/debug/Build-Database.sh +0 -12
- package/debug/Harness-Configuration.json +0 -51
- package/debug/model/doc/Dictionary.md +0 -18
- package/debug/model/doc/Model-Author.md +0 -20
- package/debug/model/doc/Model-Book.md +0 -26
- package/debug/model/doc/Model-BookAuthorJoin.md +0 -14
- package/debug/model/doc/Model-BookPrice.md +0 -25
- package/debug/model/doc/Model-Review.md +0 -22
- package/debug/model/doc/ModelChangeTracking.md +0 -17
- package/debug/model/doc/diagrams/Relationships.dot +0 -13
- package/debug/model/doc/diagrams/Relationships.png +0 -0
- package/debug/model/doc/diagrams/RelationshipsFull.dot +0 -13
- package/debug/model/doc/diagrams/RelationshipsFull.png +0 -0
- package/debug/model/mysql_create/MeadowModel-CreateMySQLDatabase.mysql.sql +0 -116
- package/source/Cumulation-Settings-Default.js +0 -19
- package/source/Cumulation.js +0 -90
- package/source/GraphGet.js +0 -607
- package/source/ProviderHelpers/Meadow-Provider-Helper-ALASQL.js +0 -48
- package/source/ProviderHelpers/Meadow-Provider-Helper-Base.js +0 -46
- package/source/ProviderHelpers/Meadow-Provider-Helper-MySQL.js +0 -62
- package/test/basic_test_configurations/fable-config-load_model.json +0 -45
- package/test/model/meadow_model/BookStore-PICT.json +0 -1
- package/test/model/meadow_model/README.md +0 -1
- /package/debug/model/{MeadowModel-Extended.json → Model-Extended.json} +0 -0
- /package/debug/model/{MeadowModel-PICT.json → Model-PICT.json} +0 -0
- /package/debug/model/{MeadowModel.json → Model.json} +0 -0
- /package/debug/{Model.ddl → model/ddl/BookStore.ddl} +0 -0
- /package/{test → debug}/model/generated_diagram/README.md +0 -0
- /package/{test → debug}/model/generated_diagram/Stricture_Output.dot +0 -0
- /package/{test → debug}/model/generated_diagram/Stricture_Output.png +0 -0
- /package/{test → debug}/model/generated_documentation/Dictionary.md +0 -0
- /package/{test → debug}/model/generated_documentation/Model-Author.md +0 -0
- /package/{test → debug}/model/generated_documentation/Model-Book.md +0 -0
- /package/{test → debug}/model/generated_documentation/Model-BookAuthorJoin.md +0 -0
- /package/{test → debug}/model/generated_documentation/Model-BookPrice.md +0 -0
- /package/{test → debug}/model/generated_documentation/Model-Review.md +0 -0
- /package/{test → debug}/model/generated_documentation/ModelChangeTracking.md +0 -0
- /package/{test → debug}/model/generated_documentation/README.md +0 -0
- /package/{test → debug}/model/manual_scripts/DropTables.sql +0 -0
- /package/{test → debug}/model/manual_scripts/README.md +0 -0
- /package/debug/model/meadow/{MeadowSchemaAuthor.json → Model-MeadowSchema-Author.json} +0 -0
- /package/debug/model/meadow/{MeadowSchemaBook.json → Model-MeadowSchema-Book.json} +0 -0
- /package/debug/model/meadow/{MeadowSchemaBookAuthorJoin.json → Model-MeadowSchema-BookAuthorJoin.json} +0 -0
- /package/debug/model/meadow/{MeadowSchemaBookPrice.json → Model-MeadowSchema-BookPrice.json} +0 -0
- /package/debug/model/meadow/{MeadowSchemaReview.json → Model-MeadowSchema-Review.json} +0 -0
- /package/{test/model/meadow_schema → debug/model/meadow}/README.md +0 -0
- /package/{test → debug}/model/sql_create/BookStore-CreateDatabase.mysql.sql +0 -0
- /package/{test → debug}/model/sql_create/README.md +0 -0
- /package/test/model/{meadow_model/BookStore-Extended.json → Model-Extended.json} +0 -0
- /package/test/model/{meadow_model/BookStore.json → Model.json} +0 -0
- /package/test/model/{meadow_schema/BookStore-MeadowSchema-Author.json → meadow/Model-MeadowSchema-Author.json} +0 -0
- /package/test/model/{meadow_schema/BookStore-MeadowSchema-Book.json → meadow/Model-MeadowSchema-Book.json} +0 -0
- /package/test/model/{meadow_schema/BookStore-MeadowSchema-BookAuthorJoin.json → meadow/Model-MeadowSchema-BookAuthorJoin.json} +0 -0
- /package/test/model/{meadow_schema/BookStore-MeadowSchema-BookPrice.json → meadow/Model-MeadowSchema-BookPrice.json} +0 -0
- /package/test/model/{meadow_schema/BookStore-MeadowSchema-Review.json → meadow/Model-MeadowSchema-Review.json} +0 -0
package/package.json
CHANGED
|
@@ -1,43 +1,60 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
2
|
+
"name": "retold-data-service",
|
|
3
|
+
"version": "1.0.4",
|
|
4
|
+
"description": "Serve up a whole model!",
|
|
5
|
+
"main": "source/Retold-Data-Service.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "node source/Retold-Data-Service.js",
|
|
8
|
+
"coverage": "./node_modules/.bin/nyc --reporter=lcov --reporter=text-lcov ./node_modules/mocha/bin/_mocha -- -u tdd -R spec",
|
|
9
|
+
"test": "./node_modules/.bin/mocha -u tdd -R spec",
|
|
10
|
+
"build": "npx quack build",
|
|
11
|
+
"docker-dev-build": "docker build ./ -f Dockerfile_LUXURYCode -t retold-data-service-image:local",
|
|
12
|
+
"docker-dev-run": "docker run -it -d --name retold-data-service-dev -p 44444:8080 -p 43306:3306 -p 8086:8086 -v \"$PWD/.config:/home/coder/.config\" -v \"$PWD:/home/coder/retold-data-service\" -u \"$(id -u):$(id -g)\" -e \"DOCKER_USER=$USER\" retold-data-service-image:local",
|
|
13
|
+
"docker-dev-shell": "docker exec -it retold-data-service-dev /bin/bash"
|
|
14
|
+
},
|
|
15
|
+
"mocha": {
|
|
16
|
+
"diff": true,
|
|
17
|
+
"extension": [
|
|
18
|
+
"js"
|
|
19
|
+
],
|
|
20
|
+
"package": "./package.json",
|
|
21
|
+
"reporter": "spec",
|
|
22
|
+
"slow": "75",
|
|
23
|
+
"timeout": "5000",
|
|
24
|
+
"ui": "tdd",
|
|
25
|
+
"watch-files": [
|
|
26
|
+
"source/**/*.js",
|
|
27
|
+
"test/**/*.js"
|
|
28
|
+
],
|
|
29
|
+
"watch-ignore": [
|
|
30
|
+
"lib/vendor"
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "https://github.com/stevenvelozo/retold-data-service.git"
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"entity",
|
|
39
|
+
"behavior",
|
|
40
|
+
"api"
|
|
41
|
+
],
|
|
42
|
+
"author": "Steven Velozo <steven@velozo.com> (http://velozo.com/)",
|
|
43
|
+
"license": "MIT",
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/stevenvelozo/retold-data-service/issues"
|
|
46
|
+
},
|
|
47
|
+
"homepage": "https://github.com/stevenvelozo/retold-data-service",
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"quackage": "^1.0.24"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"fable": "^3.0.96",
|
|
53
|
+
"fable-serviceproviderbase": "^3.0.12",
|
|
54
|
+
"meadow": "^2.0.15",
|
|
55
|
+
"meadow-connection-mysql": "^1.0.4",
|
|
56
|
+
"meadow-endpoints": "^4.0.2",
|
|
57
|
+
"orator": "^4.0.2",
|
|
58
|
+
"orator-serviceserver-restify": "^2.0.2"
|
|
59
|
+
}
|
|
43
60
|
}
|
|
@@ -1,336 +1,200 @@
|
|
|
1
|
-
// ##### Part of the **[retold](https://stevenvelozo.github.io/retold/)** system
|
|
2
1
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
* Retold Data Service
|
|
3
|
+
*
|
|
4
|
+
* All-in-one add-ins for fable to provide endpoints.
|
|
5
|
+
*
|
|
6
|
+
* @author Steven Velozo <steven@velozo.com>
|
|
7
|
+
*/
|
|
8
|
+
const libFableServiceProviderBase = require('fable-serviceproviderbase');
|
|
9
|
+
|
|
7
10
|
const libOrator = require('orator');
|
|
11
|
+
const libOratorServiceServerRestify = require('orator-serviceserver-restify');
|
|
8
12
|
const libMeadow = require('meadow');
|
|
9
13
|
const libMeadowEndpoints = require('meadow-endpoints');
|
|
10
14
|
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Retold Data Service
|
|
17
|
-
*
|
|
18
|
-
* Load all schemas from a model, and serve up the endpoints. Provide join autofills, graph
|
|
19
|
-
* solver and other data niceties.
|
|
20
|
-
*
|
|
21
|
-
* Configuration stanza expectation:
|
|
22
|
-
RetoldDataService: {
|
|
23
|
-
SchemaFile: 'SchemaFileLocation',
|
|
24
|
-
-- OR --
|
|
25
|
-
Schema: [{ ... schemas in here ... }, { ... more schemas ... }],
|
|
26
|
-
|
|
27
|
-
AutoLoad: true,
|
|
28
|
-
|
|
29
|
-
MapExtraEndpoints: true,
|
|
15
|
+
const defaultDataServiceSettings = (
|
|
16
|
+
{
|
|
17
|
+
FullMeadowSchemaPath: `${process.cwd()}/model/`,
|
|
18
|
+
FullMeadowSchemaFilename: `Model-Extended.json`,
|
|
30
19
|
|
|
31
|
-
|
|
32
|
-
|
|
20
|
+
DALMeadowSchemaPath: `${process.cwd()}/model/meadow/`,
|
|
21
|
+
DALMeadowSchemaPrefix: `Model-MeadowSchema-`,
|
|
22
|
+
DALMeadowSchemaPostfix: ``,
|
|
33
23
|
|
|
24
|
+
AutoStartOrator: true
|
|
25
|
+
});
|
|
34
26
|
|
|
35
|
-
|
|
36
|
-
* serves the entire schema graph.
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* @class RetoldDataService
|
|
40
|
-
*/
|
|
41
|
-
class RetoldDataService
|
|
27
|
+
class RetoldDataService extends libFableServiceProviderBase
|
|
42
28
|
{
|
|
43
|
-
constructor(
|
|
29
|
+
constructor(pFable, pManifest, pServiceHash)
|
|
44
30
|
{
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
this._Orator = libOrator.new(tmpConfiguration);
|
|
48
|
-
|
|
49
|
-
this._Fable = this._Orator.fable;
|
|
50
|
-
this._Settings = this._Fable.settings;
|
|
51
|
-
|
|
52
|
-
this._Meadow = libMeadow.new(this._Fable);
|
|
53
|
-
this._MeadowModelGraph = {};
|
|
31
|
+
super(pFable, pManifest, pServiceHash);
|
|
54
32
|
|
|
55
|
-
|
|
56
|
-
this._MeadowEndpoints = {};
|
|
33
|
+
this.serviceType = 'RetoldDataService';
|
|
57
34
|
|
|
58
|
-
this.
|
|
59
|
-
|
|
60
|
-
this._GraphSolver = false;
|
|
35
|
+
this.options = this.fable.Utility.extend(defaultDataServiceSettings, this.options);
|
|
36
|
+
}
|
|
61
37
|
|
|
62
|
-
|
|
38
|
+
onBeforeInitializeAsync(fCallback)
|
|
39
|
+
{
|
|
40
|
+
this.onBeforeInitialize();
|
|
41
|
+
return fCallback();
|
|
42
|
+
}
|
|
43
|
+
onBeforeInitialize()
|
|
44
|
+
{
|
|
45
|
+
this.log.info("Retold Data Service Application is beginning initialization...");
|
|
46
|
+
}
|
|
63
47
|
|
|
64
|
-
|
|
65
|
-
|
|
48
|
+
initializeAsync(fCallback)
|
|
49
|
+
{
|
|
50
|
+
if (this.serviceInitialized)
|
|
66
51
|
{
|
|
67
|
-
|
|
68
|
-
{
|
|
69
|
-
// One or many full Model file path(s) has been set
|
|
70
|
-
this._Settings.Retold.MeadowModel = `${process.cwd()}/model/MeadowModel.json`;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (this._Settings.Retold.hasOwnProperty('MeadowEntitySchemaPrefix'))
|
|
74
|
-
{
|
|
75
|
-
// One or many Entity Schema file path(s) is set
|
|
76
|
-
this._Settings.Retold.MeadowEntitySchemaPrefix = `${process.cwd()}/model/meadow/MeadowSchema`;
|
|
77
|
-
}
|
|
52
|
+
this.fable.log.error("Retold Data Service Application is being initialized but has already been initialized...");
|
|
78
53
|
}
|
|
79
54
|
else
|
|
80
55
|
{
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
// (e.g. connect to MySQL)
|
|
88
|
-
"AutoConnectProvider": true,
|
|
89
|
-
// This setting will automatically connect the backplane endpoints
|
|
90
|
-
"AutoMapBackplaneEndpoints": true,
|
|
91
|
-
// This setting will automatically map the entity endpoints when entities are loaded
|
|
92
|
-
"AutoMapEntityEndpoints": true,
|
|
93
|
-
// This setting autostarts the orator server
|
|
94
|
-
"AutoStartAPIServer": true,
|
|
95
|
-
|
|
96
|
-
// These allow the deeper behaviors of the provider helpers (e.g. creating tables)
|
|
97
|
-
"AllowDatabaseCreate": false,
|
|
98
|
-
"AllowTableCreate": false,
|
|
99
|
-
"AllowTableUpdate": false,
|
|
100
|
-
|
|
101
|
-
// This will never work because the base provider just uses English.
|
|
102
|
-
// Maybe switch to ALASQL by default for stateless services.
|
|
103
|
-
"DefaultMeadowDataProvider": "Base",
|
|
104
|
-
|
|
105
|
-
// Either the Meadow side or Stricture side should be set.
|
|
106
|
-
// Try to use the opinionated Stricture locations if they arent (you really should set this though!)
|
|
107
|
-
"MeadowModel": `${process.cwd()}/model/MeadowModel.json`,
|
|
108
|
-
"MeadowEntitySchemaPrefix": `${process.cwd()}/model/meadow/MeadowSchema`,
|
|
109
|
-
|
|
110
|
-
"StrictureDDL": false
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
this.initialize();
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
initialize(fCallback)
|
|
118
|
-
{
|
|
119
|
-
let tmpCallback = (typeof(fCallback) == 'function') ? fCallback : ()=>{};
|
|
120
|
-
libAsync.waterfall(
|
|
121
|
-
[
|
|
122
|
-
(fStageComplete) =>
|
|
56
|
+
let tmpAnticipate = this.fable.instantiateServiceProviderWithoutRegistration('Anticipate');
|
|
57
|
+
// Phase I: Allow the API host to inject behavior before anything magic happens.
|
|
58
|
+
tmpAnticipate.anticipate(this.onBeforeInitializeAsync.bind(this));
|
|
59
|
+
// Phase II: Make sure there is an Orator server available so we can put the behaviors somewhere
|
|
60
|
+
tmpAnticipate.anticipate(
|
|
61
|
+
function (fCallback)
|
|
123
62
|
{
|
|
124
|
-
if
|
|
63
|
+
// Check if Fable already has an Orator service provider, otherwise add one.
|
|
64
|
+
if (!this.fable.serviceClasses.hasOwnProperty('OratorServiceServer'))
|
|
125
65
|
{
|
|
126
|
-
this.
|
|
66
|
+
this.fable.serviceManager.addAndInstantiateServiceType('OratorServiceServer', libOratorServiceServerRestify, this.fable.settings);
|
|
127
67
|
}
|
|
128
|
-
|
|
129
|
-
return fStageComplete();
|
|
130
|
-
},
|
|
131
|
-
(fStageComplete) =>
|
|
132
|
-
{
|
|
133
|
-
if (this._Settings.Retold.AutoConnectProvider)
|
|
68
|
+
else if (!this.fable.OratorServiceServer)
|
|
134
69
|
{
|
|
135
|
-
this.
|
|
70
|
+
this.fable.serviceManager.instantiateServiceProvider('OratorServiceServer', this.fable.settings);
|
|
136
71
|
}
|
|
137
|
-
return
|
|
138
|
-
}
|
|
139
|
-
|
|
72
|
+
return fCallback();
|
|
73
|
+
}.bind(this));
|
|
74
|
+
tmpAnticipate.anticipate(
|
|
75
|
+
function (fCallback)
|
|
140
76
|
{
|
|
141
|
-
if
|
|
77
|
+
// Check if Fable already has an Orator service provider, otherwise add one.
|
|
78
|
+
if (!this.fable.serviceClasses.hasOwnProperty('Orator'))
|
|
142
79
|
{
|
|
143
|
-
this.
|
|
80
|
+
this.fable.serviceManager.addAndInstantiateServiceType('Orator', libOrator, this.fable.settings);
|
|
144
81
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
82
|
+
else if (!this.fable.Orator)
|
|
83
|
+
{
|
|
84
|
+
this.fable.serviceManager.instantiateServiceProvider('Orator', this.fable.settings);
|
|
85
|
+
}
|
|
86
|
+
return fCallback();
|
|
87
|
+
}.bind(this));
|
|
88
|
+
// Phase III: Initialize orator
|
|
89
|
+
tmpAnticipate.anticipate(this.fable.Orator.initialize.bind(this.fable.Orator));
|
|
90
|
+
// Phase IV: Initialize Meadow (this will simplify greatly when meadow and meadow-endpoints are service-ized)
|
|
91
|
+
tmpAnticipate.anticipate(
|
|
92
|
+
function (fCallback)
|
|
149
93
|
{
|
|
150
|
-
//
|
|
151
|
-
this.
|
|
152
|
-
|
|
153
|
-
//
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
94
|
+
// TODO: This code will be much cleaner with meadow and meadow-endpoints as a service. They are the only toolchain that is left!
|
|
95
|
+
this._Meadow = libMeadow.new(_Fable);
|
|
96
|
+
|
|
97
|
+
// Create DAL objects for each table in the schema
|
|
98
|
+
// These will be unnecessary when meadow and meadow-endpoints are full fledged fable services and then
|
|
99
|
+
// refactored to auto-initialize on a schema provider.
|
|
100
|
+
// For now, this is a mock of how we expect that service to provide interfaces to DAL objects.
|
|
101
|
+
this._DAL = {};
|
|
102
|
+
this.fable.DAL = this._DAL;
|
|
103
|
+
// And a mock of how the endpoints will be expressed.
|
|
104
|
+
this._MeadowEndpoints = {};
|
|
105
|
+
this.fable.MeadowEndpoints = this._MeadowEndpoints;
|
|
106
|
+
|
|
107
|
+
// TODO: This goes away when the above use services in a sane fashion.
|
|
108
|
+
// Load the mysql connection for meadow if it doesn't exist yet
|
|
109
|
+
_Fable.serviceManager.addAndInstantiateServiceType('MeadowMySQLProvider', require('meadow-connection-mysql'));
|
|
110
|
+
|
|
111
|
+
this.fullModel = false;
|
|
112
|
+
this.entityList = false;
|
|
113
|
+
|
|
114
|
+
this.serviceInitialized = false;
|
|
115
|
+
|
|
116
|
+
return fCallback();
|
|
117
|
+
}.bind(this));
|
|
118
|
+
// Phase V: Initialize the meat of the matter (the retold data service)
|
|
119
|
+
tmpAnticipate.anticipate(
|
|
120
|
+
function(fCallback)
|
|
121
|
+
{
|
|
122
|
+
this.fable.log.info("Retold Data Service DAL methods initializing...");
|
|
162
123
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
GraphRequestEntity: tmpGraphRequestEntity,
|
|
169
|
-
GraphRequestFilter: tmpGraphRequestFilter,
|
|
124
|
+
// Create DAL objects for each table in the schema
|
|
125
|
+
// 1. Load full compiled schema of the model from stricture
|
|
126
|
+
_Fable.log.info(`...loading full model stricture schema...`);
|
|
127
|
+
this.fullModel = require (`${this.options.FullMeadowSchemaPath}${this.options.FullMeadowSchemaFilename}`);
|
|
128
|
+
_Fable.log.info(`...full model stricture schema loaded.`);
|
|
170
129
|
|
|
171
|
-
|
|
130
|
+
// 2. Extract an array of each table in the schema
|
|
131
|
+
_Fable.log.info(`...getting entity list...`);
|
|
132
|
+
this.entityList = Object.keys(this.fullModel.Tables);
|
|
172
133
|
|
|
173
|
-
|
|
174
|
-
|
|
134
|
+
// 3. Enumerate each entry in the compiled model and load a DAL for that table
|
|
135
|
+
_Fable.log.info(`...initializing ${this.entityList.length} DAL objects and corresponding Meadow Endpoints...`);
|
|
136
|
+
for (let i = 0; i < this.entityList.length; i++)
|
|
137
|
+
{
|
|
138
|
+
// 4. Create the DAL for each entry (e.g. it would be at _DAL.Movie for the Movie entity)
|
|
139
|
+
let tmpDALEntityName = this.entityList[i];
|
|
140
|
+
let tmpDALPackageFile = `${this.options.DALMeadowSchemaPath}${this.options.DALMeadowSchemaPrefix}${tmpDALEntityName}${this.options.DALMeadowSchemaPostfix}.json`
|
|
141
|
+
_Fable.log.info(`Initializing the ${tmpDALEntityName} DAL from [${tmpDALPackageFile}]...`);
|
|
142
|
+
this._DAL[tmpDALEntityName] = this._Meadow.loadFromPackage(tmpDALPackageFile);
|
|
143
|
+
// 5. Tell this DAL object to use MySQL
|
|
144
|
+
_Fable.log.info(`...defaulting the ${tmpDALEntityName} DAL to use MySQL`);
|
|
145
|
+
this._DAL[tmpDALEntityName].setProvider('MySQL');
|
|
146
|
+
// 6. Create a Meadow Endpoints class for this DAL
|
|
147
|
+
_Fable.log.info(`...initializing the ${tmpDALEntityName} Meadow Endpoints to use MySQL`);
|
|
148
|
+
this._MeadowEndpoints[tmpDALEntityName] = libMeadowEndpoints.new(this._DAL[tmpDALEntityName]);
|
|
149
|
+
// 8. Expose the meadow endpoints on Orator
|
|
150
|
+
_Fable.log.info(`...mapping the ${tmpDALEntityName} Meadow Endpoints to Orator`);
|
|
151
|
+
this._MeadowEndpoints[tmpDALEntityName].connectRoutes(this.fable.Orator.webServer);
|
|
152
|
+
}
|
|
175
153
|
|
|
176
|
-
|
|
177
|
-
ValidIdentities: pValidIdentities,
|
|
154
|
+
this.serviceInitialized = true;
|
|
178
155
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
return fStageComplete();
|
|
186
|
-
},
|
|
187
|
-
(fStageComplete) =>
|
|
156
|
+
return fCallback();
|
|
157
|
+
}.bind(this));
|
|
158
|
+
// Phase VI: Optionally auto start the orator server.
|
|
159
|
+
tmpAnticipate.anticipate(
|
|
160
|
+
function (fCallback)
|
|
188
161
|
{
|
|
189
|
-
if (this.
|
|
162
|
+
if (this.options.AutoStartOrator)
|
|
190
163
|
{
|
|
191
|
-
this.
|
|
164
|
+
this.fable.log.info(`The Retold Data Service is Auto Starting Orator...`);
|
|
165
|
+
this.fable.Orator.startWebServer(fCallback);
|
|
192
166
|
}
|
|
193
167
|
else
|
|
194
168
|
{
|
|
195
|
-
return
|
|
169
|
+
return fCallback();
|
|
196
170
|
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
(pError)=>
|
|
200
|
-
{
|
|
201
|
-
if (pError)
|
|
202
|
-
{
|
|
203
|
-
this._Fable.log.error('Error initializing Retold Data Service: '+pError.toString(), pError);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
tmpCallback(pError);
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
initializeDefaultProvider()
|
|
211
|
-
{
|
|
212
|
-
let libProvider = require(`./ProviderHelpers/Meadow-Provider-Helper-${this._Settings.Retold.DefaultMeadowDataProvider}.js`);
|
|
213
|
-
|
|
214
|
-
// This is to support multiple providers
|
|
215
|
-
this._Providers.Default = new libProvider(this._Fable);
|
|
216
|
-
|
|
217
|
-
return this._Providers.Default.connect();
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
initializeGraphEndpoints()
|
|
221
|
-
{
|
|
222
|
-
this._GraphSolver = new libGraphSolver(this._Fable, this._MeadowModelGraph);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
mapBackplaneEndpoints()
|
|
226
|
-
{
|
|
227
|
-
const tmpBackplanePrefix = 'BACKPLANE';
|
|
228
|
-
// Pull version from the config file.
|
|
229
|
-
const tmpEndpointVersion = this._Fable.settings.MeadowEndpointVersion || '1.0';
|
|
230
|
-
|
|
231
|
-
const tmpBackplaneEndpointPrefix = `/${tmpBackplanePrefix}/${tmpEndpointVersion}`;
|
|
232
|
-
|
|
233
|
-
// TODO: Break this out into separate classes
|
|
234
|
-
this._Orator.webServer.get(`${tmpBackplaneEndpointPrefix}/Model`,
|
|
235
|
-
(pRequest, pResponse, fNext) =>
|
|
236
|
-
{
|
|
237
|
-
pResponse.send(this._MeadowModelGraph);
|
|
238
|
-
return fNext();
|
|
239
|
-
});
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// Lock the service to a specific session (this will bypass auth)
|
|
243
|
-
lockServiceSession(pSessionData)
|
|
244
|
-
{
|
|
245
|
-
if (typeof(pSessionData) != 'object')
|
|
246
|
-
{
|
|
247
|
-
this.log.error(`Error locking service session -- invalid object passed in.`, pSessionData);
|
|
248
|
-
return false;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
_Fable.log.info(`...Creating Mock User Session and adding it to all requests on Restify/Orator`, pSessionData);
|
|
252
|
-
var fMockAuthentication = (pRequest, pResponse, fNext) =>
|
|
253
|
-
{
|
|
254
|
-
pRequest.UserSession = pSessionData;
|
|
255
|
-
fNext();
|
|
256
|
-
};
|
|
257
|
-
this._Orator.webServer.use(fMockAuthentication);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// Load models based on what's in the configuration
|
|
261
|
-
loadModels()
|
|
262
|
-
{
|
|
263
|
-
if (this._Settings.Retold.MeadowModel)
|
|
264
|
-
{
|
|
265
|
-
this.loadMeadowModelFile(this._Settings.Retold.MeadowModel);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
171
|
+
}.bind(this));
|
|
172
|
+
tmpAnticipate.anticipate(this.onAfterInitializeAsync.bind(this));
|
|
268
173
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
this.log.error(`Could not load Meadow model object: Invalid object passed.`, pModelObject);
|
|
283
|
-
return false;
|
|
284
|
-
}
|
|
285
|
-
if (!pModelObject.hasOwnProperty('Tables')
|
|
286
|
-
|| typeof(pModelObject.Tables) != 'object')
|
|
287
|
-
{
|
|
288
|
-
this.log.error(`Could not load Meadow model object: Object does not contain a Tables property.`, pModelObject);
|
|
289
|
-
return false;
|
|
290
|
-
}
|
|
291
|
-
// 2. Extract an array of each table in the schema
|
|
292
|
-
let tmpModelTableList = Object.keys(pModelObject.Tables);
|
|
293
|
-
let tmpDefaultProvider = (this._Fable.settings.Retold.DefaultMeadowDataProvider) ? this._Fable.settings.Retold.DefaultMeadowDataProvider : 'Base';
|
|
294
|
-
// 3. Enumerate each entry in the compiled model and load a DAL for that table
|
|
295
|
-
this.log.info(`...Creating ${tmpModelTableList.length} DAL entries...`);
|
|
296
|
-
for (let i = 0; i < tmpModelTableList.length; i++)
|
|
297
|
-
{
|
|
298
|
-
let tmpDALEntityName = tmpModelTableList[i];
|
|
299
|
-
this.log.info(` -> Creating the [${tmpDALEntityName}] DAL...`);
|
|
300
|
-
// 4. Create the DAL for each entry (e.g. it would be at _DAL.Book or _DAL.Author)
|
|
301
|
-
// TODO: I don't like this ... stricture should just generate a huge file of these in an array, which could be loaded with the new injector
|
|
302
|
-
this._DAL[tmpDALEntityName] = this._Meadow.loadFromPackage(`${this._Settings.Retold.MeadowEntitySchemaPrefix}${tmpDALEntityName}.json`);
|
|
303
|
-
// 5. Tell this DAL object to use the default provider
|
|
304
|
-
this._DAL[tmpDALEntityName].setProvider(tmpDefaultProvider);
|
|
305
|
-
// 6. Create a Meadow Endpoints class for this DAL
|
|
306
|
-
this._MeadowEndpoints[tmpDALEntityName] = libMeadowEndpoints.new(this._DAL[tmpDALEntityName]);
|
|
307
|
-
// 7. Expose the meadow endpoints on Orator
|
|
308
|
-
if (this._Fable.settings.Retold.AutoMapEntityEndpoints)
|
|
309
|
-
{
|
|
310
|
-
this._MeadowEndpoints[tmpDALEntityName].connectRoutes(this._Orator.webServer);
|
|
311
|
-
this._MeadowEndpoints[tmpDALEntityName].RoutesConnected = true;
|
|
312
|
-
}
|
|
174
|
+
// Now anticipate (wait for) initialization to complete.
|
|
175
|
+
tmpAnticipate.wait(
|
|
176
|
+
function (pError)
|
|
177
|
+
{
|
|
178
|
+
if (pError)
|
|
179
|
+
{
|
|
180
|
+
let tmpErrorMessage = `Error initializing Retold Data Service: ${pError}`;
|
|
181
|
+
this.log.error(tmpErrorMessage);
|
|
182
|
+
// TODO: Should this bubble up? I think not.
|
|
183
|
+
throw new Error(tmpErrorMessage);
|
|
184
|
+
}
|
|
185
|
+
return fCallback();
|
|
186
|
+
}.bind(this));
|
|
313
187
|
}
|
|
314
188
|
}
|
|
315
189
|
|
|
316
|
-
|
|
317
|
-
{
|
|
318
|
-
this._Orator.startWebServer(fCallback);
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
get orator()
|
|
190
|
+
onAfterInitializeAsync(fCallback)
|
|
322
191
|
{
|
|
323
|
-
|
|
192
|
+
this.onAfterInitialize();
|
|
193
|
+
return fCallback();
|
|
324
194
|
}
|
|
325
|
-
|
|
326
|
-
get fable()
|
|
327
|
-
{
|
|
328
|
-
return this._Fable;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
get settings()
|
|
195
|
+
onAfterInitialize()
|
|
332
196
|
{
|
|
333
|
-
|
|
197
|
+
this.log.info("Retold Data Service Application has completed an initialization attempt.");
|
|
334
198
|
}
|
|
335
199
|
}
|
|
336
200
|
|
|
@@ -8,9 +8,10 @@
|
|
|
8
8
|
|
|
9
9
|
var Chai = require("chai");
|
|
10
10
|
var Expect = Chai.expect;
|
|
11
|
-
var Assert = Chai.assert;
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
const libFable = require('fable');
|
|
13
|
+
|
|
14
|
+
const _Settings = require(`./model/fable-configuration.json`);
|
|
14
15
|
|
|
15
16
|
suite
|
|
16
17
|
(
|
|
@@ -24,47 +25,29 @@ suite
|
|
|
24
25
|
'Object Sanity',
|
|
25
26
|
function()
|
|
26
27
|
{
|
|
27
|
-
test
|
|
28
|
-
(
|
|
29
|
-
'The class should initialize itself into a happy little object.',
|
|
30
|
-
function()
|
|
31
|
-
{
|
|
32
|
-
testService = new libRetoldDataService({"Product":"SimpleInitializationTest"});
|
|
33
|
-
|
|
34
|
-
// Instantiate the logger
|
|
35
|
-
Expect(testService).to.be.an('object', 'The data service should initialize as an object directly from the require statement and minimal configuration.');
|
|
36
|
-
Expect(testService).to.have.a.property('log')
|
|
37
|
-
.that.is.a('object');
|
|
38
|
-
Expect(testService).to.have.a.property('settings')
|
|
39
|
-
.that.is.a('object');
|
|
40
|
-
Expect(testService).to.have.a.property('fable')
|
|
41
|
-
.that.is.a('object');
|
|
42
|
-
Expect(testService).to.have.a.property('orator')
|
|
43
|
-
.that.is.a('object');
|
|
44
|
-
Expect(testService.settings.Product)
|
|
45
|
-
.to.equal('SimpleInitializationTest')
|
|
46
|
-
}
|
|
47
|
-
);
|
|
48
28
|
test
|
|
49
29
|
(
|
|
50
30
|
'Change some settings later...',
|
|
51
31
|
function(fDone)
|
|
52
32
|
{
|
|
53
|
-
|
|
33
|
+
_Fable = new libFable(_Settings);
|
|
34
|
+
_Fable.serviceManager.addServiceType('RetoldDataService', require('../source/Retold-Data-Service.js'));
|
|
35
|
+
let tmpRetoldDataService = _Fable.serviceManager.instantiateServiceProvider('RetoldDataService',
|
|
36
|
+
{
|
|
37
|
+
FullMeadowSchemaPath: `${process.cwd()}/test/model/`,
|
|
38
|
+
DALMeadowSchemaPath: `${process.cwd()}/test/model/meadow/`,
|
|
39
|
+
|
|
40
|
+
AutoInitializeDataService: true,
|
|
41
|
+
AutoStartOrator: true
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
Expect(tmpRetoldDataService).to.be.an('object', 'Retold Data Service should initialize as an object.');
|
|
54
45
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
.to.equal('0.0.0');
|
|
61
|
-
// Now change a setting by merging in something new
|
|
62
|
-
testService.fable.settingsManager.merge({Product:'TestProduct'});
|
|
63
|
-
Expect(testService.settings.Product)
|
|
64
|
-
.to.equal('TestProduct');
|
|
65
|
-
Expect(testService.settings.ProductVersion)
|
|
66
|
-
.to.equal('0.0.0');
|
|
67
|
-
fDone();
|
|
46
|
+
tmpRetoldDataService.initializeAsync(
|
|
47
|
+
function(pError)
|
|
48
|
+
{
|
|
49
|
+
return fDone();
|
|
50
|
+
});
|
|
68
51
|
}
|
|
69
52
|
);
|
|
70
53
|
}
|