retold-data-service 2.0.13 → 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/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,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retold Data Service - Meadow Integration Service
|
|
3
|
+
*
|
|
4
|
+
* Fable service that exposes meadow-integration capabilities via REST
|
|
5
|
+
* endpoints under /1.0/Retold/MeadowIntegration/.
|
|
6
|
+
*
|
|
7
|
+
* Uses a dedicated Pict instance (which extends Fable with parseTemplate,
|
|
8
|
+
* ExpressionParser, CSVParser, etc.) for integration operations.
|
|
9
|
+
*
|
|
10
|
+
* @author Steven Velozo <steven@velozo.com>
|
|
11
|
+
*/
|
|
12
|
+
const libFableServiceProviderBase = require('fable-serviceproviderbase');
|
|
13
|
+
|
|
14
|
+
const libPict = require('pict');
|
|
15
|
+
const libPath = require('path');
|
|
16
|
+
|
|
17
|
+
// Resolve the meadow-integration package root so we can require internal files
|
|
18
|
+
const _MeadowIntegrationBase = libPath.dirname(require.resolve('meadow-integration/package.json'));
|
|
19
|
+
|
|
20
|
+
// Require meadow-integration service providers from their resolved paths
|
|
21
|
+
const libTabularCheck = require(libPath.join(_MeadowIntegrationBase, 'source/services/tabular/Service-TabularCheck.js'));
|
|
22
|
+
const libTabularTransform = require(libPath.join(_MeadowIntegrationBase, 'source/services/tabular/Service-TabularTransform.js'));
|
|
23
|
+
const libIntegrationAdapter = require(libPath.join(_MeadowIntegrationBase, 'source/Meadow-Service-Integration-Adapter.js'));
|
|
24
|
+
|
|
25
|
+
const _RoutePrefix = '/1.0/Retold/MeadowIntegration';
|
|
26
|
+
|
|
27
|
+
class RetoldDataServiceMeadowIntegration extends libFableServiceProviderBase
|
|
28
|
+
{
|
|
29
|
+
constructor(pFable, pOptions, pServiceHash)
|
|
30
|
+
{
|
|
31
|
+
super(pFable, pOptions, pServiceHash);
|
|
32
|
+
|
|
33
|
+
this.serviceType = 'RetoldDataServiceMeadowIntegration';
|
|
34
|
+
|
|
35
|
+
// Create a dedicated Pict instance for integration operations.
|
|
36
|
+
// Pict extends Fable with parseTemplate, ExpressionParser, CSVParser,
|
|
37
|
+
// DataFormat, and other features required by meadow-integration services.
|
|
38
|
+
this._Pict = new libPict(
|
|
39
|
+
{
|
|
40
|
+
Product: 'RetoldDataServiceMeadowIntegration',
|
|
41
|
+
LogStreams: pFable.settings.LogStreams || [{ streamtype: 'console' }]
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Pre-initialize built-in Pict services used by integration operations
|
|
45
|
+
this._Pict.instantiateServiceProvider('CSVParser');
|
|
46
|
+
this._Pict.instantiateServiceProvider('FilePersistence');
|
|
47
|
+
this._Pict.instantiateServiceProvider('DataGeneration');
|
|
48
|
+
|
|
49
|
+
// Register meadow-integration service types on the Pict instance
|
|
50
|
+
this._Pict.addAndInstantiateServiceTypeIfNotExists('MeadowIntegrationTabularCheck', libTabularCheck);
|
|
51
|
+
this._Pict.addAndInstantiateServiceTypeIfNotExists('MeadowIntegrationTabularTransform', libTabularTransform);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The Pict instance used for integration operations.
|
|
56
|
+
* Command files use this to access parseTemplate, CSVParser,
|
|
57
|
+
* TabularCheck, TabularTransform, etc.
|
|
58
|
+
*/
|
|
59
|
+
get pict()
|
|
60
|
+
{
|
|
61
|
+
return this._Pict;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The route prefix for all MeadowIntegration endpoints.
|
|
66
|
+
*/
|
|
67
|
+
get routePrefix()
|
|
68
|
+
{
|
|
69
|
+
return _RoutePrefix;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The Integration Adapter class (used by ComprehensionPush).
|
|
74
|
+
*/
|
|
75
|
+
get IntegrationAdapter()
|
|
76
|
+
{
|
|
77
|
+
return libIntegrationAdapter;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Register all meadow integration REST routes on the Orator service server.
|
|
82
|
+
*
|
|
83
|
+
* @param {Object} pOratorServiceServer - The Orator ServiceServer instance
|
|
84
|
+
*/
|
|
85
|
+
connectRoutes(pOratorServiceServer)
|
|
86
|
+
{
|
|
87
|
+
// CSV operations
|
|
88
|
+
require('./MeadowIntegration-Command-CSVCheck.js')(this, pOratorServiceServer);
|
|
89
|
+
require('./MeadowIntegration-Command-CSVTransform.js')(this, pOratorServiceServer);
|
|
90
|
+
|
|
91
|
+
// TSV operations
|
|
92
|
+
require('./MeadowIntegration-Command-TSVCheck.js')(this, pOratorServiceServer);
|
|
93
|
+
require('./MeadowIntegration-Command-TSVTransform.js')(this, pOratorServiceServer);
|
|
94
|
+
|
|
95
|
+
// JSON Array operations
|
|
96
|
+
require('./MeadowIntegration-Command-JSONArrayTransform.js')(this, pOratorServiceServer);
|
|
97
|
+
|
|
98
|
+
// Comprehension operations
|
|
99
|
+
require('./MeadowIntegration-Command-ComprehensionIntersect.js')(this, pOratorServiceServer);
|
|
100
|
+
require('./MeadowIntegration-Command-ComprehensionToArray.js')(this, pOratorServiceServer);
|
|
101
|
+
require('./MeadowIntegration-Command-ComprehensionToCSV.js')(this, pOratorServiceServer);
|
|
102
|
+
require('./MeadowIntegration-Command-ComprehensionPush.js')(this, pOratorServiceServer);
|
|
103
|
+
|
|
104
|
+
// Entity operations
|
|
105
|
+
require('./MeadowIntegration-Command-EntityFromTabularFolder.js')(this, pOratorServiceServer);
|
|
106
|
+
|
|
107
|
+
this.fable.log.info('Retold Data Service Meadow Integration routes registered.');
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
module.exports = RetoldDataServiceMeadowIntegration;
|
|
112
|
+
module.exports.serviceType = 'RetoldDataServiceMeadowIntegration';
|
|
113
|
+
module.exports.default_configuration = {};
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MigrationManager Command - Connection Management
|
|
3
|
+
*
|
|
4
|
+
* Routes for database connection CRUD, testing, introspection, and
|
|
5
|
+
* provider listing.
|
|
6
|
+
*
|
|
7
|
+
* GET /api/providers
|
|
8
|
+
* GET /api/connections
|
|
9
|
+
* POST /api/connections
|
|
10
|
+
* DELETE /api/connections/:name
|
|
11
|
+
* POST /api/connections/:name/test
|
|
12
|
+
* POST /api/connections/test
|
|
13
|
+
* POST /api/connections/:name/introspect
|
|
14
|
+
*/
|
|
15
|
+
module.exports = function(pMigrationService, pOratorServiceServer)
|
|
16
|
+
{
|
|
17
|
+
let tmpConnectionLibrary = pMigrationService._connectionLibrary;
|
|
18
|
+
let tmpDatabaseProviderFactory = pMigrationService._databaseProviderFactory;
|
|
19
|
+
let tmpSchemaLibrary = pMigrationService._schemaLibrary;
|
|
20
|
+
let tmpPrefix = pMigrationService.routePrefix;
|
|
21
|
+
|
|
22
|
+
// GET /api/providers — list available database provider types
|
|
23
|
+
pOratorServiceServer.get(tmpPrefix + '/api/providers',
|
|
24
|
+
(pRequest, pResponse, fNext) =>
|
|
25
|
+
{
|
|
26
|
+
try
|
|
27
|
+
{
|
|
28
|
+
pResponse.send(
|
|
29
|
+
{
|
|
30
|
+
Success: true,
|
|
31
|
+
Providers: tmpDatabaseProviderFactory.listAvailableProviders()
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
catch (pError)
|
|
35
|
+
{
|
|
36
|
+
pResponse.send(500, { Success: false, Error: pError.message });
|
|
37
|
+
}
|
|
38
|
+
return fNext();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// GET /api/connections — list all saved connections
|
|
42
|
+
pOratorServiceServer.get(tmpPrefix + '/api/connections',
|
|
43
|
+
(pRequest, pResponse, fNext) =>
|
|
44
|
+
{
|
|
45
|
+
try
|
|
46
|
+
{
|
|
47
|
+
let tmpNames = tmpConnectionLibrary.listConnections();
|
|
48
|
+
let tmpConnections = [];
|
|
49
|
+
|
|
50
|
+
for (let i = 0; i < tmpNames.length; i++)
|
|
51
|
+
{
|
|
52
|
+
let tmpEntry = tmpConnectionLibrary.getConnection(tmpNames[i]);
|
|
53
|
+
tmpConnections.push(
|
|
54
|
+
{
|
|
55
|
+
Name: tmpEntry.Name,
|
|
56
|
+
Type: tmpEntry.Type,
|
|
57
|
+
Config:
|
|
58
|
+
{
|
|
59
|
+
server: tmpEntry.Config.server || tmpEntry.Config.host || '',
|
|
60
|
+
port: tmpEntry.Config.port || '',
|
|
61
|
+
user: tmpEntry.Config.user || '',
|
|
62
|
+
database: tmpEntry.Config.database || ''
|
|
63
|
+
// Intentionally omit password
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
pResponse.send({ Success: true, Connections: tmpConnections });
|
|
69
|
+
}
|
|
70
|
+
catch (pError)
|
|
71
|
+
{
|
|
72
|
+
pResponse.send(500, { Success: false, Error: pError.message });
|
|
73
|
+
}
|
|
74
|
+
return fNext();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// POST /api/connections — add a new connection
|
|
78
|
+
pOratorServiceServer.post(tmpPrefix + '/api/connections',
|
|
79
|
+
(pRequest, pResponse, fNext) =>
|
|
80
|
+
{
|
|
81
|
+
try
|
|
82
|
+
{
|
|
83
|
+
let tmpName = pRequest.body && pRequest.body.Name;
|
|
84
|
+
let tmpType = pRequest.body && pRequest.body.Type;
|
|
85
|
+
let tmpConfig = pRequest.body && pRequest.body.Config;
|
|
86
|
+
|
|
87
|
+
if (!tmpName || !tmpType || !tmpConfig)
|
|
88
|
+
{
|
|
89
|
+
pResponse.send(400, { Success: false, Error: 'Name, Type, and Config are required.' });
|
|
90
|
+
return fNext();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
tmpConnectionLibrary.addConnection(tmpName, tmpType, tmpConfig);
|
|
94
|
+
|
|
95
|
+
pResponse.send({ Success: true, Name: tmpName });
|
|
96
|
+
}
|
|
97
|
+
catch (pError)
|
|
98
|
+
{
|
|
99
|
+
pResponse.send(500, { Success: false, Error: pError.message });
|
|
100
|
+
}
|
|
101
|
+
return fNext();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// DELETE /api/connections/:name — remove a connection
|
|
105
|
+
pOratorServiceServer.del(tmpPrefix + '/api/connections/:name',
|
|
106
|
+
(pRequest, pResponse, fNext) =>
|
|
107
|
+
{
|
|
108
|
+
try
|
|
109
|
+
{
|
|
110
|
+
let tmpRemoved = tmpConnectionLibrary.removeConnection(pRequest.params.name);
|
|
111
|
+
|
|
112
|
+
if (!tmpRemoved)
|
|
113
|
+
{
|
|
114
|
+
pResponse.send(404, { Success: false, Error: `Connection [${pRequest.params.name}] not found.` });
|
|
115
|
+
return fNext();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
pResponse.send({ Success: true });
|
|
119
|
+
}
|
|
120
|
+
catch (pError)
|
|
121
|
+
{
|
|
122
|
+
pResponse.send(500, { Success: false, Error: pError.message });
|
|
123
|
+
}
|
|
124
|
+
return fNext();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// POST /api/connections/:name/test — test a saved connection
|
|
128
|
+
pOratorServiceServer.post(tmpPrefix + '/api/connections/:name/test',
|
|
129
|
+
(pRequest, pResponse, fNext) =>
|
|
130
|
+
{
|
|
131
|
+
tmpDatabaseProviderFactory.testConnection(pRequest.params.name,
|
|
132
|
+
(pError, pTableList) =>
|
|
133
|
+
{
|
|
134
|
+
if (pError)
|
|
135
|
+
{
|
|
136
|
+
pResponse.send(500, { Success: false, Error: `Connection test failed: ${pError.message || pError}` });
|
|
137
|
+
return fNext();
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
pResponse.send(
|
|
141
|
+
{
|
|
142
|
+
Success: true,
|
|
143
|
+
TableCount: pTableList.length,
|
|
144
|
+
Tables: pTableList
|
|
145
|
+
});
|
|
146
|
+
return fNext();
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// POST /api/connections/test — test an unsaved connection config
|
|
151
|
+
pOratorServiceServer.post(tmpPrefix + '/api/connections/test',
|
|
152
|
+
(pRequest, pResponse, fNext) =>
|
|
153
|
+
{
|
|
154
|
+
let tmpType = pRequest.body && pRequest.body.Type;
|
|
155
|
+
let tmpConfig = pRequest.body && pRequest.body.Config;
|
|
156
|
+
|
|
157
|
+
if (!tmpType || !tmpConfig)
|
|
158
|
+
{
|
|
159
|
+
pResponse.send(400, { Success: false, Error: 'Type and Config are required.' });
|
|
160
|
+
return fNext();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
tmpDatabaseProviderFactory.testConnectionConfig(tmpType, tmpConfig,
|
|
164
|
+
(pError, pTableList) =>
|
|
165
|
+
{
|
|
166
|
+
if (pError)
|
|
167
|
+
{
|
|
168
|
+
pResponse.send(500, { Success: false, Error: `Connection test failed: ${pError.message || pError}` });
|
|
169
|
+
return fNext();
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
pResponse.send(
|
|
173
|
+
{
|
|
174
|
+
Success: true,
|
|
175
|
+
TableCount: pTableList.length,
|
|
176
|
+
Tables: pTableList
|
|
177
|
+
});
|
|
178
|
+
return fNext();
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// POST /api/connections/:name/introspect — introspect a saved connection
|
|
183
|
+
pOratorServiceServer.post(tmpPrefix + '/api/connections/:name/introspect',
|
|
184
|
+
(pRequest, pResponse, fNext) =>
|
|
185
|
+
{
|
|
186
|
+
tmpDatabaseProviderFactory.introspectConnection(pRequest.params.name,
|
|
187
|
+
(pError, pSchema) =>
|
|
188
|
+
{
|
|
189
|
+
if (pError)
|
|
190
|
+
{
|
|
191
|
+
pResponse.send(500, { Success: false, Error: `Introspection failed: ${pError.message || pError}` });
|
|
192
|
+
return fNext();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
let tmpSaveAs = pRequest.body && pRequest.body.saveAs;
|
|
196
|
+
|
|
197
|
+
if (tmpSaveAs)
|
|
198
|
+
{
|
|
199
|
+
let tmpEntry = tmpSchemaLibrary.addSchema(tmpSaveAs, '');
|
|
200
|
+
tmpEntry.CompiledSchema = pSchema;
|
|
201
|
+
tmpEntry.LastCompiled = new Date().toJSON();
|
|
202
|
+
|
|
203
|
+
pResponse.send(
|
|
204
|
+
{
|
|
205
|
+
Success: true,
|
|
206
|
+
Schema: pSchema,
|
|
207
|
+
SavedAs: tmpSaveAs
|
|
208
|
+
});
|
|
209
|
+
return fNext();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
pResponse.send(
|
|
213
|
+
{
|
|
214
|
+
Success: true,
|
|
215
|
+
Schema: pSchema
|
|
216
|
+
});
|
|
217
|
+
return fNext();
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
};
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MigrationManager Command - Diff & Migration
|
|
3
|
+
*
|
|
4
|
+
* Routes for schema diffing and SQL migration script generation.
|
|
5
|
+
*
|
|
6
|
+
* POST /api/schemas/diff
|
|
7
|
+
* POST /api/schemas/generate-migration
|
|
8
|
+
*/
|
|
9
|
+
module.exports = function(pMigrationService, pOratorServiceServer)
|
|
10
|
+
{
|
|
11
|
+
let tmpSchemaLibrary = pMigrationService._schemaLibrary;
|
|
12
|
+
let tmpSchemaDiff = pMigrationService._schemaDiff;
|
|
13
|
+
let tmpMigrationGenerator = pMigrationService._migrationGenerator;
|
|
14
|
+
let tmpDatabaseProviderFactory = pMigrationService._databaseProviderFactory;
|
|
15
|
+
let tmpPrefix = pMigrationService.routePrefix;
|
|
16
|
+
|
|
17
|
+
// POST /api/schemas/diff — diff two schemas (DDL↔DDL, DDL↔DB, DB↔DB)
|
|
18
|
+
pOratorServiceServer.post(tmpPrefix + '/api/schemas/diff',
|
|
19
|
+
(pRequest, pResponse, fNext) =>
|
|
20
|
+
{
|
|
21
|
+
let tmpSourceName = pRequest.body && pRequest.body.source;
|
|
22
|
+
let tmpTargetName = pRequest.body && pRequest.body.target;
|
|
23
|
+
let tmpSourceConnection = pRequest.body && pRequest.body.sourceConnection;
|
|
24
|
+
let tmpTargetConnection = pRequest.body && pRequest.body.targetConnection;
|
|
25
|
+
|
|
26
|
+
// Resolve the source side
|
|
27
|
+
let fResolveSource = (fDone) =>
|
|
28
|
+
{
|
|
29
|
+
if (tmpSourceConnection)
|
|
30
|
+
{
|
|
31
|
+
tmpDatabaseProviderFactory.introspectConnection(tmpSourceConnection,
|
|
32
|
+
(pError, pSchema) =>
|
|
33
|
+
{
|
|
34
|
+
if (pError)
|
|
35
|
+
{
|
|
36
|
+
return fDone(pError);
|
|
37
|
+
}
|
|
38
|
+
return fDone(null, pSchema, `DB:${tmpSourceConnection}`);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
else if (tmpSourceName)
|
|
42
|
+
{
|
|
43
|
+
let tmpSourceEntry = tmpSchemaLibrary.getSchema(tmpSourceName);
|
|
44
|
+
|
|
45
|
+
if (!tmpSourceEntry)
|
|
46
|
+
{
|
|
47
|
+
return fDone(new Error(`Source schema [${tmpSourceName}] not found.`));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (!tmpSourceEntry.CompiledSchema)
|
|
51
|
+
{
|
|
52
|
+
return fDone(new Error(`Source schema [${tmpSourceName}] has not been compiled.`));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return fDone(null, pMigrationService.normalizeSchemaForDiff(tmpSourceEntry.CompiledSchema), tmpSourceName);
|
|
56
|
+
}
|
|
57
|
+
else
|
|
58
|
+
{
|
|
59
|
+
return fDone(new Error('Either source or sourceConnection is required.'));
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// Resolve the target side
|
|
64
|
+
let fResolveTarget = (fDone) =>
|
|
65
|
+
{
|
|
66
|
+
if (tmpTargetConnection)
|
|
67
|
+
{
|
|
68
|
+
tmpDatabaseProviderFactory.introspectConnection(tmpTargetConnection,
|
|
69
|
+
(pError, pSchema) =>
|
|
70
|
+
{
|
|
71
|
+
if (pError)
|
|
72
|
+
{
|
|
73
|
+
return fDone(pError);
|
|
74
|
+
}
|
|
75
|
+
return fDone(null, pSchema, `DB:${tmpTargetConnection}`);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
else if (tmpTargetName)
|
|
79
|
+
{
|
|
80
|
+
let tmpTargetEntry = tmpSchemaLibrary.getSchema(tmpTargetName);
|
|
81
|
+
|
|
82
|
+
if (!tmpTargetEntry)
|
|
83
|
+
{
|
|
84
|
+
return fDone(new Error(`Target schema [${tmpTargetName}] not found.`));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (!tmpTargetEntry.CompiledSchema)
|
|
88
|
+
{
|
|
89
|
+
return fDone(new Error(`Target schema [${tmpTargetName}] has not been compiled.`));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return fDone(null, pMigrationService.normalizeSchemaForDiff(tmpTargetEntry.CompiledSchema), tmpTargetName);
|
|
93
|
+
}
|
|
94
|
+
else
|
|
95
|
+
{
|
|
96
|
+
return fDone(new Error('Either target or targetConnection is required.'));
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
fResolveSource(
|
|
101
|
+
(pSourceError, pSourceSchema, pSourceLabel) =>
|
|
102
|
+
{
|
|
103
|
+
if (pSourceError)
|
|
104
|
+
{
|
|
105
|
+
pResponse.send(400, { Success: false, Error: pSourceError.message });
|
|
106
|
+
return fNext();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
fResolveTarget(
|
|
110
|
+
(pTargetError, pTargetSchema, pTargetLabel) =>
|
|
111
|
+
{
|
|
112
|
+
if (pTargetError)
|
|
113
|
+
{
|
|
114
|
+
pResponse.send(400, { Success: false, Error: pTargetError.message });
|
|
115
|
+
return fNext();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
try
|
|
119
|
+
{
|
|
120
|
+
let tmpDiffResult = tmpSchemaDiff.diffSchemas(pSourceSchema, pTargetSchema);
|
|
121
|
+
|
|
122
|
+
pResponse.send(
|
|
123
|
+
{
|
|
124
|
+
Success: true,
|
|
125
|
+
Source: pSourceLabel,
|
|
126
|
+
Target: pTargetLabel,
|
|
127
|
+
Diff: tmpDiffResult
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
catch (pDiffError)
|
|
131
|
+
{
|
|
132
|
+
pResponse.send(500, { Success: false, Error: pDiffError.message });
|
|
133
|
+
}
|
|
134
|
+
return fNext();
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// POST /api/schemas/generate-migration — generate SQL migration script
|
|
140
|
+
pOratorServiceServer.post(tmpPrefix + '/api/schemas/generate-migration',
|
|
141
|
+
(pRequest, pResponse, fNext) =>
|
|
142
|
+
{
|
|
143
|
+
try
|
|
144
|
+
{
|
|
145
|
+
let tmpDiff = pRequest.body && pRequest.body.diff;
|
|
146
|
+
let tmpDatabaseType = (pRequest.body && pRequest.body.databaseType) || 'MySQL';
|
|
147
|
+
|
|
148
|
+
if (!tmpDiff)
|
|
149
|
+
{
|
|
150
|
+
pResponse.send(400, { Success: false, Error: 'A diff result object is required.' });
|
|
151
|
+
return fNext();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
let tmpScript = tmpMigrationGenerator.generateMigrationScript(tmpDiff, tmpDatabaseType);
|
|
155
|
+
|
|
156
|
+
pResponse.send(
|
|
157
|
+
{
|
|
158
|
+
Success: true,
|
|
159
|
+
DatabaseType: tmpDatabaseType,
|
|
160
|
+
Script: tmpScript
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
catch (pError)
|
|
164
|
+
{
|
|
165
|
+
pResponse.send(500, { Success: false, Error: pError.message });
|
|
166
|
+
}
|
|
167
|
+
return fNext();
|
|
168
|
+
});
|
|
169
|
+
};
|