retold-data-service 2.0.12 → 2.0.14
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/README.md +64 -55
- package/docs/README.md +24 -66
- package/docs/_cover.md +7 -7
- package/docs/_sidebar.md +24 -11
- package/docs/_topbar.md +2 -0
- package/docs/api/constructor.md +67 -0
- package/docs/api/initializeDataEndpoints.md +54 -0
- package/docs/api/initializePersistenceEngine.md +34 -0
- package/docs/api/initializeService.md +44 -0
- package/docs/api/onAfterInitialize.md +48 -0
- package/docs/api/onBeforeInitialize.md +45 -0
- package/docs/api/onInitialize.md +38 -0
- package/docs/api/reference.md +35 -0
- package/docs/api/stopService.md +34 -0
- package/docs/architecture.md +78 -14
- package/docs/behavior-injection.md +121 -78
- package/docs/css/docuserve.css +73 -0
- package/docs/dal-access.md +135 -56
- package/docs/index.html +1 -1
- package/docs/quick-start.md +169 -0
- package/docs/retold-catalog.json +144 -0
- package/docs/retold-keyword-index.json +3530 -0
- package/example_applications/data-cloner/data/cloned.sqlite +0 -0
- package/example_applications/data-cloner/data/cloned.sqlite-shm +0 -0
- package/example_applications/data-cloner/data/cloned.sqlite-wal +0 -0
- package/example_applications/data-cloner/data-cloner-web.html +935 -0
- package/example_applications/data-cloner/data-cloner.js +1047 -0
- package/example_applications/data-cloner/package.json +19 -0
- package/package.json +13 -9
- package/source/Retold-Data-Service.js +225 -73
- package/source/services/Retold-Data-Service-ConnectionManager.js +277 -0
- package/source/services/Retold-Data-Service-MeadowEndpoints.js +217 -0
- package/source/services/Retold-Data-Service-ModelManager.js +335 -0
- package/source/services/meadow-integration/MeadowIntegration-Command-CSVCheck.js +85 -0
- package/source/services/meadow-integration/MeadowIntegration-Command-CSVTransform.js +180 -0
- package/source/services/meadow-integration/MeadowIntegration-Command-ComprehensionIntersect.js +153 -0
- package/source/services/meadow-integration/MeadowIntegration-Command-ComprehensionPush.js +190 -0
- package/source/services/meadow-integration/MeadowIntegration-Command-ComprehensionToArray.js +113 -0
- package/source/services/meadow-integration/MeadowIntegration-Command-ComprehensionToCSV.js +211 -0
- package/source/services/meadow-integration/MeadowIntegration-Command-EntityFromTabularFolder.js +244 -0
- package/source/services/meadow-integration/MeadowIntegration-Command-JSONArrayTransform.js +213 -0
- package/source/services/meadow-integration/MeadowIntegration-Command-TSVCheck.js +80 -0
- package/source/services/meadow-integration/MeadowIntegration-Command-TSVTransform.js +166 -0
- package/source/services/meadow-integration/Retold-Data-Service-MeadowIntegration.js +113 -0
- package/source/services/migration-manager/MigrationManager-Command-Connections.js +220 -0
- package/source/services/migration-manager/MigrationManager-Command-DiffMigrate.js +169 -0
- package/source/services/migration-manager/MigrationManager-Command-Schemas.js +532 -0
- package/source/services/migration-manager/MigrationManager-Command-WebUI.js +123 -0
- package/source/services/migration-manager/Retold-Data-Service-MigrationManager.js +357 -0
- package/source/services/stricture/Retold-Data-Service-Stricture.js +303 -0
- package/source/services/stricture/Stricture-Command-Compile.js +39 -0
- package/source/services/stricture/Stricture-Command-Generate-AuthorizationChart.js +14 -0
- package/source/services/stricture/Stricture-Command-Generate-DictionaryCSV.js +14 -0
- package/source/services/stricture/Stricture-Command-Generate-LaTeX.js +14 -0
- package/source/services/stricture/Stricture-Command-Generate-Markdown.js +14 -0
- package/source/services/stricture/Stricture-Command-Generate-Meadow.js +14 -0
- package/source/services/stricture/Stricture-Command-Generate-ModelGraph.js +14 -0
- package/source/services/stricture/Stricture-Command-Generate-MySQL.js +14 -0
- package/source/services/stricture/Stricture-Command-Generate-MySQLMigrate.js +14 -0
- package/source/services/stricture/Stricture-Command-Generate-Pict.js +14 -0
- package/source/services/stricture/Stricture-Command-Generate-TestObjectContainers.js +14 -0
- package/test/RetoldDataService_tests.js +161 -1
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retold Data Service - Connection Manager
|
|
3
|
+
*
|
|
4
|
+
* Fable service that manages named database connections.
|
|
5
|
+
* Each connection has a name, provider type, provider module,
|
|
6
|
+
* configuration, and active status.
|
|
7
|
+
*
|
|
8
|
+
* Provides REST endpoints under /1.0/Retold/Connection(s) for
|
|
9
|
+
* managing connections at runtime.
|
|
10
|
+
*
|
|
11
|
+
* @author Steven Velozo <steven@velozo.com>
|
|
12
|
+
*/
|
|
13
|
+
const libFableServiceProviderBase = require('fable-serviceproviderbase');
|
|
14
|
+
|
|
15
|
+
class RetoldDataServiceConnectionManager extends libFableServiceProviderBase
|
|
16
|
+
{
|
|
17
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
18
|
+
{
|
|
19
|
+
super(pFable, pOptions, pServiceHash);
|
|
20
|
+
|
|
21
|
+
this.serviceType = 'RetoldDataServiceConnectionManager';
|
|
22
|
+
|
|
23
|
+
// Named connection storage: { connectionName: { Name, Provider, ProviderModule, Config, Active } }
|
|
24
|
+
this.connections = {};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Add a named connection. Stores the definition and instantiates the
|
|
29
|
+
* provider service in fable.
|
|
30
|
+
*
|
|
31
|
+
* @param {string} pName - Connection name
|
|
32
|
+
* @param {Object} pConnectionDefinition - Connection config object
|
|
33
|
+
* @param {string} pConnectionDefinition.Provider - Provider name (e.g. 'SQLite', 'MySQL')
|
|
34
|
+
* @param {string} pConnectionDefinition.ProviderModule - npm module name (e.g. 'meadow-connection-sqlite')
|
|
35
|
+
* @param {Object} pConnectionDefinition.Config - Provider-specific configuration
|
|
36
|
+
* @param {function} fCallback - Callback invoked as fCallback(pError)
|
|
37
|
+
*/
|
|
38
|
+
addConnection(pName, pConnectionDefinition, fCallback)
|
|
39
|
+
{
|
|
40
|
+
if (!pName || typeof(pName) !== 'string')
|
|
41
|
+
{
|
|
42
|
+
return fCallback(new Error('Connection name is required and must be a string.'));
|
|
43
|
+
}
|
|
44
|
+
if (!pConnectionDefinition || !pConnectionDefinition.Provider || !pConnectionDefinition.ProviderModule)
|
|
45
|
+
{
|
|
46
|
+
return fCallback(new Error('Connection definition must include Provider and ProviderModule.'));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (this.connections.hasOwnProperty(pName))
|
|
50
|
+
{
|
|
51
|
+
this.fable.log.warn(`Connection [${pName}] already exists; overwriting.`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let tmpConnection = (
|
|
55
|
+
{
|
|
56
|
+
Name: pName,
|
|
57
|
+
Provider: pConnectionDefinition.Provider,
|
|
58
|
+
ProviderModule: pConnectionDefinition.ProviderModule,
|
|
59
|
+
Config: pConnectionDefinition.Config || {},
|
|
60
|
+
Active: false
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
this.connections[pName] = tmpConnection;
|
|
64
|
+
|
|
65
|
+
// Merge config into fable settings under the provider key
|
|
66
|
+
// (e.g. fable.settings.SQLite = { SQLiteFilePath: ':memory:' })
|
|
67
|
+
if (tmpConnection.Config && Object.keys(tmpConnection.Config).length > 0)
|
|
68
|
+
{
|
|
69
|
+
this.fable.settings[tmpConnection.Provider] = this.fable.Utility.extend(
|
|
70
|
+
this.fable.settings[tmpConnection.Provider] || {},
|
|
71
|
+
tmpConnection.Config);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Instantiate the provider service
|
|
75
|
+
let tmpServiceTypeName = `Meadow${tmpConnection.Provider}Provider`;
|
|
76
|
+
try
|
|
77
|
+
{
|
|
78
|
+
this.fable.serviceManager.addAndInstantiateServiceType(tmpServiceTypeName, require(tmpConnection.ProviderModule));
|
|
79
|
+
tmpConnection.Active = true;
|
|
80
|
+
this.fable.log.info(`Connection [${pName}] added and provider [${tmpServiceTypeName}] instantiated.`);
|
|
81
|
+
}
|
|
82
|
+
catch (pError)
|
|
83
|
+
{
|
|
84
|
+
this.fable.log.error(`Error instantiating provider for connection [${pName}]: ${pError}`);
|
|
85
|
+
return fCallback(pError);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return fCallback();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Remove a named connection.
|
|
93
|
+
*
|
|
94
|
+
* @param {string} pName - Connection name
|
|
95
|
+
* @param {function} fCallback - Callback invoked as fCallback(pError)
|
|
96
|
+
*/
|
|
97
|
+
removeConnection(pName, fCallback)
|
|
98
|
+
{
|
|
99
|
+
if (!this.connections.hasOwnProperty(pName))
|
|
100
|
+
{
|
|
101
|
+
return fCallback(new Error(`Connection [${pName}] does not exist.`));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
delete this.connections[pName];
|
|
105
|
+
this.fable.log.info(`Connection [${pName}] removed.`);
|
|
106
|
+
return fCallback();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Test a named connection by verifying the provider service exists and is reachable.
|
|
111
|
+
*
|
|
112
|
+
* @param {string} pName - Connection name
|
|
113
|
+
* @param {function} fCallback - Callback invoked as fCallback(pError, pResult)
|
|
114
|
+
*/
|
|
115
|
+
testConnection(pName, fCallback)
|
|
116
|
+
{
|
|
117
|
+
if (!this.connections.hasOwnProperty(pName))
|
|
118
|
+
{
|
|
119
|
+
return fCallback(new Error(`Connection [${pName}] does not exist.`));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
let tmpConnection = this.connections[pName];
|
|
123
|
+
let tmpServiceTypeName = `Meadow${tmpConnection.Provider}Provider`;
|
|
124
|
+
|
|
125
|
+
// Check that the provider service is available in fable
|
|
126
|
+
let tmpProviderService = this.fable[tmpServiceTypeName];
|
|
127
|
+
if (!tmpProviderService)
|
|
128
|
+
{
|
|
129
|
+
return fCallback(null, { Connection: pName, Status: 'Error', Message: `Provider service [${tmpServiceTypeName}] not found in fable.` });
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// If the provider has a connected property, check it
|
|
133
|
+
if (typeof(tmpProviderService.connected) !== 'undefined')
|
|
134
|
+
{
|
|
135
|
+
return fCallback(null, { Connection: pName, Status: tmpProviderService.connected ? 'Connected' : 'Disconnected', Provider: tmpConnection.Provider });
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Provider exists but no connected flag
|
|
139
|
+
return fCallback(null, { Connection: pName, Status: 'Available', Provider: tmpConnection.Provider });
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Get a single connection's metadata (without sensitive config details).
|
|
144
|
+
*
|
|
145
|
+
* @param {string} pName - Connection name
|
|
146
|
+
* @return {Object|false} Connection metadata or false if not found
|
|
147
|
+
*/
|
|
148
|
+
getConnection(pName)
|
|
149
|
+
{
|
|
150
|
+
if (!this.connections.hasOwnProperty(pName))
|
|
151
|
+
{
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
let tmpConnection = this.connections[pName];
|
|
156
|
+
return (
|
|
157
|
+
{
|
|
158
|
+
Name: tmpConnection.Name,
|
|
159
|
+
Provider: tmpConnection.Provider,
|
|
160
|
+
Active: tmpConnection.Active
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Get summary metadata for all connections.
|
|
166
|
+
*
|
|
167
|
+
* @return {Array} Array of connection summaries
|
|
168
|
+
*/
|
|
169
|
+
getConnections()
|
|
170
|
+
{
|
|
171
|
+
let tmpConnectionList = [];
|
|
172
|
+
let tmpConnectionNames = Object.keys(this.connections);
|
|
173
|
+
|
|
174
|
+
for (let i = 0; i < tmpConnectionNames.length; i++)
|
|
175
|
+
{
|
|
176
|
+
tmpConnectionList.push(this.getConnection(tmpConnectionNames[i]));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return tmpConnectionList;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Register REST routes for connection management on the Orator service server.
|
|
184
|
+
*
|
|
185
|
+
* @param {Object} pOratorServiceServer - The Orator ServiceServer instance
|
|
186
|
+
*/
|
|
187
|
+
connectRoutes(pOratorServiceServer)
|
|
188
|
+
{
|
|
189
|
+
let tmpSelf = this;
|
|
190
|
+
|
|
191
|
+
// GET /1.0/Retold/Connections — list all connections
|
|
192
|
+
pOratorServiceServer.get('/1.0/Retold/Connections',
|
|
193
|
+
(pRequest, pResponse, fNext) =>
|
|
194
|
+
{
|
|
195
|
+
pResponse.send(200, tmpSelf.getConnections());
|
|
196
|
+
return fNext();
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// GET /1.0/Retold/Connection/:Name — get a single connection
|
|
200
|
+
pOratorServiceServer.get('/1.0/Retold/Connection/:Name',
|
|
201
|
+
(pRequest, pResponse, fNext) =>
|
|
202
|
+
{
|
|
203
|
+
let tmpConnection = tmpSelf.getConnection(pRequest.params.Name);
|
|
204
|
+
if (!tmpConnection)
|
|
205
|
+
{
|
|
206
|
+
pResponse.send(404, { Error: `Connection [${pRequest.params.Name}] not found.` });
|
|
207
|
+
return fNext();
|
|
208
|
+
}
|
|
209
|
+
pResponse.send(200, tmpConnection);
|
|
210
|
+
return fNext();
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
// POST /1.0/Retold/Connection — add a connection
|
|
214
|
+
pOratorServiceServer.postWithBodyParser('/1.0/Retold/Connection',
|
|
215
|
+
(pRequest, pResponse, fNext) =>
|
|
216
|
+
{
|
|
217
|
+
let tmpBody = pRequest.body;
|
|
218
|
+
if (!tmpBody || !tmpBody.Name)
|
|
219
|
+
{
|
|
220
|
+
pResponse.send(400, { Error: 'Request body must include Name, Provider, and ProviderModule.' });
|
|
221
|
+
return fNext();
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
tmpSelf.addConnection(tmpBody.Name, tmpBody,
|
|
225
|
+
(pError) =>
|
|
226
|
+
{
|
|
227
|
+
if (pError)
|
|
228
|
+
{
|
|
229
|
+
pResponse.send(500, { Error: pError.message });
|
|
230
|
+
return fNext();
|
|
231
|
+
}
|
|
232
|
+
pResponse.send(200, tmpSelf.getConnection(tmpBody.Name));
|
|
233
|
+
return fNext();
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
// DEL /1.0/Retold/Connection/:Name — remove a connection
|
|
238
|
+
pOratorServiceServer.del('/1.0/Retold/Connection/:Name',
|
|
239
|
+
(pRequest, pResponse, fNext) =>
|
|
240
|
+
{
|
|
241
|
+
tmpSelf.removeConnection(pRequest.params.Name,
|
|
242
|
+
(pError) =>
|
|
243
|
+
{
|
|
244
|
+
if (pError)
|
|
245
|
+
{
|
|
246
|
+
pResponse.send(404, { Error: pError.message });
|
|
247
|
+
return fNext();
|
|
248
|
+
}
|
|
249
|
+
pResponse.send(200, { Message: `Connection [${pRequest.params.Name}] removed.` });
|
|
250
|
+
return fNext();
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// GET /1.0/Retold/Connection/:Name/Test — test a connection
|
|
255
|
+
pOratorServiceServer.get('/1.0/Retold/Connection/:Name/Test',
|
|
256
|
+
(pRequest, pResponse, fNext) =>
|
|
257
|
+
{
|
|
258
|
+
tmpSelf.testConnection(pRequest.params.Name,
|
|
259
|
+
(pError, pResult) =>
|
|
260
|
+
{
|
|
261
|
+
if (pError)
|
|
262
|
+
{
|
|
263
|
+
pResponse.send(404, { Error: pError.message });
|
|
264
|
+
return fNext();
|
|
265
|
+
}
|
|
266
|
+
pResponse.send(200, pResult);
|
|
267
|
+
return fNext();
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
this.fable.log.info('Retold Data Service ConnectionManager routes registered.');
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
module.exports = RetoldDataServiceConnectionManager;
|
|
276
|
+
module.exports.serviceType = 'RetoldDataServiceConnectionManager';
|
|
277
|
+
module.exports.default_configuration = {};
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retold Data Service - Meadow Endpoints Service
|
|
3
|
+
*
|
|
4
|
+
* Fable service responsible for loading compiled model schemas,
|
|
5
|
+
* creating DAL objects and Meadow Endpoints for each entity,
|
|
6
|
+
* and connecting their routes to Orator.
|
|
7
|
+
*
|
|
8
|
+
* Supports loading multiple named models. All entities across
|
|
9
|
+
* all models are merged into flat _DAL and _MeadowEndpoints maps.
|
|
10
|
+
*
|
|
11
|
+
* @author Steven Velozo <steven@velozo.com>
|
|
12
|
+
*/
|
|
13
|
+
const libFableServiceProviderBase = require('fable-serviceproviderbase');
|
|
14
|
+
|
|
15
|
+
const libMeadow = require('meadow');
|
|
16
|
+
const libMeadowEndpoints = require('meadow-endpoints');
|
|
17
|
+
|
|
18
|
+
const defaultMeadowEndpointsSettings = (
|
|
19
|
+
{
|
|
20
|
+
StorageProvider: 'MySQL',
|
|
21
|
+
|
|
22
|
+
FullMeadowSchemaPath: `${process.cwd()}/model/`,
|
|
23
|
+
FullMeadowSchemaFilename: `MeadowModel-Extended.json`
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
class RetoldDataServiceMeadowEndpoints extends libFableServiceProviderBase
|
|
27
|
+
{
|
|
28
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
29
|
+
{
|
|
30
|
+
let tmpOptions = Object.assign({}, JSON.parse(JSON.stringify(defaultMeadowEndpointsSettings)), pOptions);
|
|
31
|
+
super(pFable, tmpOptions, pServiceHash);
|
|
32
|
+
|
|
33
|
+
this.serviceType = 'RetoldDataServiceMeadowEndpoints';
|
|
34
|
+
|
|
35
|
+
this._Meadow = libMeadow.new(pFable);
|
|
36
|
+
|
|
37
|
+
this._DAL = {};
|
|
38
|
+
this._MeadowEndpoints = {};
|
|
39
|
+
|
|
40
|
+
// Named model storage -- each key is a model name, value is the parsed model object
|
|
41
|
+
this.models = {};
|
|
42
|
+
|
|
43
|
+
// Merged view across all models (rebuilt on each loadModel call)
|
|
44
|
+
this.fullModel = false;
|
|
45
|
+
this.entityList = false;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Rebuild the merged fullModel and entityList from all loaded models.
|
|
50
|
+
*
|
|
51
|
+
* Called internally after each loadModel to keep the merged view current.
|
|
52
|
+
*/
|
|
53
|
+
rebuildFullModel()
|
|
54
|
+
{
|
|
55
|
+
let tmpModelNames = Object.keys(this.models);
|
|
56
|
+
|
|
57
|
+
if (tmpModelNames.length === 0)
|
|
58
|
+
{
|
|
59
|
+
this.fullModel = false;
|
|
60
|
+
this.entityList = false;
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
let tmpMergedModel = (
|
|
65
|
+
{
|
|
66
|
+
Tables: {},
|
|
67
|
+
TablesSequence: [],
|
|
68
|
+
Authorization: {},
|
|
69
|
+
Endpoints: {},
|
|
70
|
+
Pict: {}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
for (let i = 0; i < tmpModelNames.length; i++)
|
|
74
|
+
{
|
|
75
|
+
let tmpModel = this.models[tmpModelNames[i]];
|
|
76
|
+
|
|
77
|
+
if (tmpModel.Tables)
|
|
78
|
+
{
|
|
79
|
+
Object.assign(tmpMergedModel.Tables, tmpModel.Tables);
|
|
80
|
+
}
|
|
81
|
+
if (tmpModel.TablesSequence)
|
|
82
|
+
{
|
|
83
|
+
tmpMergedModel.TablesSequence = tmpMergedModel.TablesSequence.concat(tmpModel.TablesSequence);
|
|
84
|
+
}
|
|
85
|
+
if (tmpModel.Authorization)
|
|
86
|
+
{
|
|
87
|
+
Object.assign(tmpMergedModel.Authorization, tmpModel.Authorization);
|
|
88
|
+
}
|
|
89
|
+
if (tmpModel.Endpoints)
|
|
90
|
+
{
|
|
91
|
+
Object.assign(tmpMergedModel.Endpoints, tmpModel.Endpoints);
|
|
92
|
+
}
|
|
93
|
+
if (tmpModel.Pict)
|
|
94
|
+
{
|
|
95
|
+
Object.assign(tmpMergedModel.Pict, tmpModel.Pict);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
this.fullModel = tmpMergedModel;
|
|
100
|
+
this.entityList = Object.keys(this._DAL);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Load a parsed model object and create DAL objects and Meadow Endpoints
|
|
105
|
+
* for each entity in it.
|
|
106
|
+
*
|
|
107
|
+
* @param {string} pModelName - A name to identify this model
|
|
108
|
+
* @param {Object} pModelObject - The parsed stricture model (MeadowModel-Extended.json format)
|
|
109
|
+
* @param {string} [pStorageProvider] - Optional storage provider name override (e.g. 'SQLite', 'MySQL')
|
|
110
|
+
* @param {function} fCallback - Callback invoked as fCallback(pError) on completion
|
|
111
|
+
*/
|
|
112
|
+
loadModel(pModelName, pModelObject, pStorageProvider, fCallback)
|
|
113
|
+
{
|
|
114
|
+
// Handle optional pStorageProvider parameter
|
|
115
|
+
let tmpCallback = fCallback;
|
|
116
|
+
let tmpStorageProvider = pStorageProvider;
|
|
117
|
+
if (typeof(pStorageProvider) === 'function')
|
|
118
|
+
{
|
|
119
|
+
tmpCallback = pStorageProvider;
|
|
120
|
+
tmpStorageProvider = this.options.StorageProvider;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
this.fable.log.info(`Retold Data Service loading model [${pModelName}]...`);
|
|
124
|
+
|
|
125
|
+
if (this.models.hasOwnProperty(pModelName))
|
|
126
|
+
{
|
|
127
|
+
this.fable.log.warn(`Model [${pModelName}] is already loaded; overwriting.`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
this.models[pModelName] = pModelObject;
|
|
131
|
+
|
|
132
|
+
let tmpEntityList = Object.keys(pModelObject.Tables);
|
|
133
|
+
|
|
134
|
+
this.fable.log.info(`...initializing ${tmpEntityList.length} DAL objects and corresponding Meadow Endpoints for model [${pModelName}]...`);
|
|
135
|
+
|
|
136
|
+
for (let i = 0; i < tmpEntityList.length; i++)
|
|
137
|
+
{
|
|
138
|
+
let tmpDALEntityName = tmpEntityList[i];
|
|
139
|
+
|
|
140
|
+
if (this._DAL.hasOwnProperty(tmpDALEntityName))
|
|
141
|
+
{
|
|
142
|
+
this.fable.log.warn(`Entity [${tmpDALEntityName}] already exists in the DAL (from another model); overwriting.`);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
try
|
|
146
|
+
{
|
|
147
|
+
let tmpDALSchema = pModelObject.Tables[tmpDALEntityName];
|
|
148
|
+
let tmpDALMeadowSchema = tmpDALSchema.MeadowSchema;
|
|
149
|
+
|
|
150
|
+
this._DAL[tmpDALEntityName] = this._Meadow.loadFromPackageObject(tmpDALMeadowSchema);
|
|
151
|
+
this.fable.log.info(`...defaulting the ${tmpDALEntityName} DAL to use ${tmpStorageProvider}`);
|
|
152
|
+
this._DAL[tmpDALEntityName].setProvider(tmpStorageProvider);
|
|
153
|
+
this.fable.log.info(`...initializing the ${tmpDALEntityName} Meadow Endpoints`);
|
|
154
|
+
this._MeadowEndpoints[tmpDALEntityName] = libMeadowEndpoints.new(this._DAL[tmpDALEntityName]);
|
|
155
|
+
this.fable.log.info(`...mapping the ${tmpDALEntityName} Meadow Endpoints to Orator`);
|
|
156
|
+
this._MeadowEndpoints[tmpDALEntityName].connectRoutes(this.fable.OratorServiceServer);
|
|
157
|
+
}
|
|
158
|
+
catch (pError)
|
|
159
|
+
{
|
|
160
|
+
this.fable.log.error(`Error initializing DAL and Endpoints for entity [${tmpDALEntityName}]: ${pError}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
this.rebuildFullModel();
|
|
165
|
+
|
|
166
|
+
return tmpCallback();
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Load a model from a JSON file on disk.
|
|
171
|
+
*
|
|
172
|
+
* @param {string} pModelName - A name to identify this model
|
|
173
|
+
* @param {string} pModelPath - Directory path containing the model file
|
|
174
|
+
* @param {string} pModelFilename - The model JSON filename
|
|
175
|
+
* @param {function} fCallback - Callback invoked as fCallback(pError) on completion
|
|
176
|
+
*/
|
|
177
|
+
loadModelFromFile(pModelName, pModelPath, pModelFilename, fCallback)
|
|
178
|
+
{
|
|
179
|
+
this.fable.log.info(`...loading model [${pModelName}] from file [${pModelPath}${pModelFilename}]...`);
|
|
180
|
+
|
|
181
|
+
let tmpModelObject;
|
|
182
|
+
try
|
|
183
|
+
{
|
|
184
|
+
tmpModelObject = require(`${pModelPath}${pModelFilename}`);
|
|
185
|
+
}
|
|
186
|
+
catch (pError)
|
|
187
|
+
{
|
|
188
|
+
this.fable.log.error(`Error loading model file [${pModelPath}${pModelFilename}]: ${pError}`);
|
|
189
|
+
return fCallback(pError);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return this.loadModel(pModelName, tmpModelObject, fCallback);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Initialize data endpoints by loading the default model from options.
|
|
197
|
+
*
|
|
198
|
+
* This is the standard initialization path used by initializeService
|
|
199
|
+
* in the main RetoldDataService. Loads a single model using the configured
|
|
200
|
+
* FullMeadowSchemaPath and FullMeadowSchemaFilename options.
|
|
201
|
+
*
|
|
202
|
+
* @param {function} fCallback - Callback invoked as fCallback(pError) on completion
|
|
203
|
+
*/
|
|
204
|
+
initializeDataEndpoints(fCallback)
|
|
205
|
+
{
|
|
206
|
+
this.fable.log.info("Retold Data Service initializing Endpoints...");
|
|
207
|
+
|
|
208
|
+
// Derive a model name from the filename (e.g. "MeadowModel-Extended.json" -> "MeadowModel-Extended")
|
|
209
|
+
let tmpModelName = this.options.FullMeadowSchemaFilename.replace(/\.json$/i, '');
|
|
210
|
+
|
|
211
|
+
return this.loadModelFromFile(tmpModelName, this.options.FullMeadowSchemaPath, this.options.FullMeadowSchemaFilename, fCallback);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
module.exports = RetoldDataServiceMeadowEndpoints;
|
|
216
|
+
module.exports.serviceType = 'RetoldDataServiceMeadowEndpoints';
|
|
217
|
+
module.exports.default_configuration = defaultMeadowEndpointsSettings;
|