dbmodel 0.1.1 → 5.2.2-alpha.11

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.
@@ -1,191 +0,0 @@
1
- const _ = require('lodash');
2
- const fs = require('fs');
3
- const endOfLine = require('os').EOL;
4
- const {
5
- getCreateTableSql,
6
- getCreateColumnSql,
7
- getCreateFkSql,
8
- getCreateIndexSql,
9
- getProjectIndexesAsDatabase,
10
- sortViewsByDependency,
11
- getFillTableSql,
12
- } = require('./getsql');
13
-
14
- function writeLine(options, data) {
15
- fs.writeSync(options.outputDescriptor, data);
16
- fs.writeSync(options.outputDescriptor, endOfLine);
17
- }
18
-
19
- function buildTables(options) {
20
- const tables = options.projectStructure.tables;
21
-
22
- for (const tableName of _.keys(tables)) {
23
- const table = tables[tableName];
24
- writeLine(options, `IF (NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='${tableName}'))`);
25
- writeLine(options, 'BEGIN');
26
- writeLine(options, `PRINT 'Creating table ${tableName}'`);
27
- writeLine(options, getCreateTableSql(table));
28
- writeLine(options, 'END');
29
- writeLine(options, 'ELSE');
30
- writeLine(options, 'BEGIN');
31
- writeLine(options, `PRINT 'Table ${tableName} already exists'`);
32
- writeLine(options, 'END');
33
- writeLine(options, 'GO');
34
-
35
- for (const column of table.columns) {
36
- writeLine(
37
- options,
38
- `IF (NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='${tableName}' AND COLUMN_NAME='${column.name}'))`
39
- );
40
- writeLine(options, 'BEGIN');
41
- writeLine(options, `PRINT 'Creating column ${tableName}.${column.name}'`);
42
- writeLine(options, getCreateColumnSql(table, column));
43
- writeLine(options, 'END');
44
- writeLine(options, 'GO');
45
- }
46
- }
47
-
48
- for (const tableName of _.keys(tables)) {
49
- const table = tables[tableName];
50
- for (const column of table.columns) {
51
- if (column.references) {
52
- writeLine(
53
- options,
54
- `IF (NOT EXISTS(
55
- SELECT *
56
- FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C
57
- INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK
58
- ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME AND c.CONSTRAINT_SCHEMA = FK.CONSTRAINT_SCHEMA
59
- LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK
60
- ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME AND c.UNIQUE_CONSTRAINT_SCHEMA = PK.CONSTRAINT_SCHEMA
61
- LEFT JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU
62
- ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME AND C.CONSTRAINT_SCHEMA = CU.CONSTRAINT_SCHEMA
63
- WHERE c.CONSTRAINT_SCHEMA = 'dbo'
64
- AND FK.TABLE_NAME='${tableName}'
65
- AND PK.TABLE_NAME='${column.references}'
66
- AND CU.COLUMN_NAME = '${column.name}'
67
- ))
68
- `
69
- );
70
- writeLine(options, 'BEGIN');
71
- writeLine(options, `PRINT 'Creating foreign key on ${tableName}.${column.name}'`);
72
- writeLine(options, getCreateFkSql(table, column, tables));
73
- writeLine(options, 'END');
74
- writeLine(options, 'GO');
75
- }
76
- }
77
- }
78
-
79
- const projectIndexArray = getProjectIndexesAsDatabase(tables);
80
-
81
- for (const index of projectIndexArray) {
82
- writeLine(
83
- options,
84
- `IF (NOT EXISTS(
85
- SELECT *
86
- FROM sys.indexes i
87
- inner join sys.objects o ON o.object_id = i.object_id
88
- WHERE i.name='${index.indexName}' and o.name='${index.tableName}'
89
- and i.is_primary_key=0
90
- and i.is_hypothetical=0 and indexproperty(i.object_id, i.name, 'IsStatistics') = 0
91
- and objectproperty(i.object_id, 'IsUserTable') = 1
92
- and i.index_id between 1 and 254
93
- ))`
94
- );
95
- writeLine(options, 'BEGIN');
96
- writeLine(options, `PRINT 'Creating index ${index.indexName} on ${index.tableName}'`);
97
- writeLine(options, getCreateIndexSql(index));
98
- writeLine(options, 'END');
99
- writeLine(options, 'GO');
100
- }
101
- }
102
-
103
- function buildObjects(
104
- options,
105
- projectObjects,
106
- objectTypeName,
107
- createRegex,
108
- createCommand,
109
- alterCommand,
110
- info_schema,
111
- info_schema_column,
112
- sortObjects
113
- ) {
114
- const sortedList = sortObjects ? sortObjects(_.keys(projectObjects), projectObjects) : _.keys(projectObjects);
115
-
116
- for (const objectName of sortedList) {
117
- const objectSql = projectObjects[objectName];
118
- writeLine(options, `DECLARE @sql NVARCHAR(MAX) = '';`);
119
-
120
- writeLine(
121
- options,
122
- `IF (NOT EXISTS(
123
- SELECT * FROM INFORMATION_SCHEMA.${info_schema} WHERE ${info_schema_column}='${objectName}'
124
- ))`
125
- );
126
- writeLine(options, 'BEGIN');
127
- writeLine(options, `PRINT 'Creating ${objectTypeName} ${objectName}'`);
128
- writeLine(options, `SET @sql = '${createCommand}';`);
129
- writeLine(options, 'END');
130
- writeLine(options, `ELSE`);
131
- writeLine(options, 'BEGIN');
132
- writeLine(options, `PRINT 'Altering ${objectTypeName} ${objectName}'`);
133
- writeLine(options, `SET @sql = '${alterCommand}';`);
134
- writeLine(options, 'END');
135
-
136
- writeLine(options, `SET @sql = @sql + ' ' + '${objectSql.replace(createRegex, '').replace(/'/g, "''")}';`);
137
- writeLine(options, `EXEC sp_executesql @sql;`);
138
- writeLine(options, 'GO');
139
- }
140
- }
141
-
142
- function buildFillTables(options) {
143
- const tables = options.projectStructure.tables;
144
- for (const tableName of _.keys(tables)) {
145
- const table = tables[tableName];
146
- const sql = getFillTableSql(table);
147
- if (!sql) continue;
148
- writeLine(options, `PRINT 'Filling table ${tableName}'`);
149
- writeLine(options, sql);
150
- }
151
- }
152
-
153
- async function build(options) {
154
- buildTables(options);
155
-
156
- buildObjects(
157
- options,
158
- options.projectStructure.views,
159
- 'view',
160
- /create\s+view/i,
161
- 'CREATE VIEW',
162
- 'ALTER VIEW',
163
- 'VIEWS',
164
- 'TABLE_NAME',
165
- sortViewsByDependency
166
- );
167
- buildObjects(
168
- options,
169
- options.projectStructure.procedures,
170
- 'procedure',
171
- /create\s+procedure/i,
172
- 'CREATE PROCEDURE',
173
- 'ALTER PROCEDURE',
174
- 'ROUTINES',
175
- 'ROUTINE_NAME'
176
- );
177
- buildObjects(
178
- options,
179
- options.projectStructure.functions,
180
- 'function',
181
- /create\s+function/i,
182
- 'CREATE FUNCTION',
183
- 'ALTER FUNCTION',
184
- 'ROUTINES',
185
- 'ROUTINE_NAME'
186
- );
187
-
188
- buildFillTables(options);
189
- }
190
-
191
- module.exports = build;
@@ -1,9 +0,0 @@
1
- const mssql = require('mssql');
2
-
3
- async function connect(options) {
4
- if (options.mssqlPool) return options; // already connected
5
- const { connection } = options;
6
- options.mssqlPool = await mssql.connect(connection);
7
- }
8
-
9
- module.exports = connect;
@@ -1,343 +0,0 @@
1
- const _ = require('lodash');
2
- const JSONNormalize = require('json-normalize');
3
- const {
4
- getColumnDefinitionSql,
5
- getCreateTableSql,
6
- getCreateColumnSql,
7
- getCreateFkSql,
8
- getCreateIndexSql,
9
- getProjectIndexesAsDatabase,
10
- getFillTableSql,
11
- sortViewsByDependency,
12
- } = require('./getsql');
13
-
14
- async function executeAndLog(options, log, command, logSql = true) {
15
- if (_.isArray(command)) {
16
- if (log) {
17
- console.log(log);
18
- }
19
- for (const cmd of command) {
20
- await executeAndLog(options, null, cmd, logSql);
21
- }
22
- } else {
23
- if (log) {
24
- console.log(log);
25
- }
26
- if (logSql) {
27
- console.log(command);
28
- }
29
-
30
- const { mssqlPool } = options;
31
- await mssqlPool.request().query(command);
32
- }
33
- }
34
-
35
- async function processAddedTables(options) {
36
- const dbTables = options.databaseStructure.mssqlModel.tables;
37
- const projectTables = options.projectStructure.tables;
38
- const adding = _.difference(Object.keys(projectTables), Object.keys(dbTables));
39
- await Promise.all(
40
- adding.map(async table => {
41
- const createSql = getCreateTableSql(projectTables[table]);
42
- await executeAndLog(options, `Adding table ${table}`, createSql);
43
- })
44
- );
45
- }
46
-
47
- async function processTableData(options) {
48
- const projectTables = options.projectStructure.tables;
49
-
50
- for (const table of _.values(projectTables)) {
51
- const sql = getFillTableSql(table);
52
- if (!sql) continue;
53
- await executeAndLog(options, `Filling table ${table.name}`, sql, false);
54
- }
55
- }
56
-
57
- async function processAddedColumns(options) {
58
- const dbTables = options.databaseStructure.mssqlModel.tables;
59
- const projectTables = options.projectStructure.tables;
60
-
61
- const both = _.intersection(Object.keys(projectTables), Object.keys(dbTables));
62
- await Promise.all(
63
- both.map(async table => {
64
- const dbTable = dbTables[table];
65
- const projectTable = projectTables[table];
66
- const adding = _.difference(
67
- projectTable.columns.map(x => x.name),
68
- dbTable.map(x => x.columnName)
69
- );
70
- await Promise.all(
71
- adding.map(async column => {
72
- const createSql = getCreateColumnSql(
73
- projectTable,
74
- projectTable.columns.find(x => x.name == column)
75
- );
76
- await executeAndLog(options, `Adding column ${column}`, createSql);
77
- })
78
- );
79
- })
80
- );
81
- }
82
-
83
- function normalizeDefaultValue(value) {
84
- if (value == null) return null;
85
- let svalue = value.toString();
86
- while (svalue.startsWith('(') && svalue.endsWith(')')) {
87
- svalue = svalue.substring(1, svalue.length - 1);
88
- }
89
- return svalue;
90
- }
91
-
92
- async function processColumnTypeUpdate(options) {
93
- const dbTables = options.databaseStructure.mssqlModel.tables;
94
- const projectTables = options.projectStructure.tables;
95
- const { suggestions } = options;
96
-
97
- const bothTables = _.intersection(Object.keys(projectTables), Object.keys(dbTables));
98
- await Promise.all(
99
- bothTables.map(async table => {
100
- const dbTable = dbTables[table];
101
- const projectTable = projectTables[table];
102
- const bothColumns = _.intersection(
103
- projectTable.columns.map(x => x.name),
104
- dbTable.map(x => x.columnName)
105
- );
106
- for (const column of bothColumns) {
107
- const projectCol = projectTable.columns.filter(x => x.name == column)[0];
108
- const dbCol = dbTable.filter(x => x.columnName == column)[0];
109
-
110
- if (!dbCol.isNullable != (projectCol.notNull || false)) {
111
- const sql = `ALTER TABLE [${table}] ALTER COLUMN ${getColumnDefinitionSql(projectTable, projectCol)};`;
112
- const message = `Changing column notNull flag ${table}.${column} from ${!dbCol.isNullable} to ${
113
- projectCol.notNull
114
- }`;
115
- suggestions.push({ sql, message });
116
- // await executeAndLog(options, message, sql);
117
- }
118
-
119
- if (dbCol.columnDefault == null && projectCol.default != null) {
120
- const sql = `ALTER TABLE [${table}] ADD CONSTRAINT [DF_${table}_${column}] DEFAULT ${projectCol.default} FOR [${column}]`;
121
- const message = `Creating default value for column ${column} from table ${table}, ${projectCol.default}`;
122
- suggestions.push({ sql, message });
123
- }
124
-
125
- if (dbCol.columnDefault != null && projectCol.default == null) {
126
- const sql = `ALTER TABLE [${table}] DROP CONSTRAINT [DF_${table}_${column}]`;
127
- const message = `Drop default value for column ${column} from table ${table}`;
128
- suggestions.push({ sql, message });
129
- }
130
-
131
- if (
132
- dbCol.columnDefault != null &&
133
- projectCol.default != null &&
134
- normalizeDefaultValue(projectCol.default) != normalizeDefaultValue(dbCol.columnDefault)
135
- ) {
136
- const sql = `ALTER TABLE [${table}] DROP CONSTRAINT [DF_${table}_${column}];ALTER TABLE [${table}] ADD CONSTRAINT [DF_${table}_${column}] DEFAULT ${projectCol.default} FOR [${column}]`;
137
- const message = `Changing default value for column ${column} from table ${table}, ${projectCol.default}`;
138
- suggestions.push({ sql, message });
139
- }
140
- }
141
- })
142
- );
143
- }
144
-
145
- async function addMissingReferences(options) {
146
- const projectTables = options.projectStructure.tables;
147
- const dbReferences = options.databaseStructure.mssqlModel.references;
148
-
149
- await Promise.all(
150
- Object.keys(projectTables).map(async table => {
151
- await Promise.all(
152
- projectTables[table].columns
153
- .filter(x => x.references)
154
- .filter(x => !dbReferences.find(y => table == y.fkTable && x.name == y.fkColumn))
155
- .map(async column => {
156
- const createSql = getCreateFkSql(projectTables[table], column, projectTables);
157
- await executeAndLog(options, `Adding foreign key ${table}.${column.name}`, createSql);
158
- })
159
- );
160
- })
161
- );
162
- }
163
-
164
- function jsonNormalizeIndex(index) {
165
- const indexCopy = { ...index };
166
- if (!indexCopy.filterDefinition) delete indexCopy.filterDefinition;
167
- delete indexCopy.continueOnError;
168
- if (indexCopy.filterDefinition) {
169
- indexCopy.filterDefinition = indexCopy.filterDefinition
170
- .replace(/\s/g, '')
171
- .replace(/\(/g, '')
172
- .replace(/\)/g, '')
173
- .replace(/\[/g, '')
174
- .replace(/\]/g, '');
175
- }
176
- return JSONNormalize.stringifySync(indexCopy);
177
- }
178
-
179
- async function processIndexes(options) {
180
- const dbIndexes = options.databaseStructure.mssqlModel.indexes;
181
- const projectTables = options.projectStructure.tables;
182
- const { suggestions } = options;
183
-
184
- const dbIndexArray = _.flatten(_.values(dbIndexes).map(it => _.values(it)));
185
- const projectIndexArray = getProjectIndexesAsDatabase(projectTables);
186
-
187
- for (const dbIndex of dbIndexArray) {
188
- const prjIndex = projectIndexArray.find(
189
- x => x.tableName === dbIndex.tableName && x.indexName === dbIndex.indexName
190
- );
191
- if (prjIndex != null && (prjIndex == null || jsonNormalizeIndex(prjIndex) != jsonNormalizeIndex(dbIndex))) {
192
- await executeAndLog(
193
- options,
194
- `Removing index ${dbIndex.indexName} on ${dbIndex.tableName}`,
195
- `DROP INDEX [${dbIndex.indexName}] ON [${dbIndex.tableName}]`
196
- );
197
- }
198
-
199
- if (prjIndex == null) {
200
- suggestions.push({
201
- message: `Index ${dbIndex.indexName} on ${dbIndex.tableName} not found in project`,
202
- sql: `DROP INDEX [${dbIndex.indexName}] ON [${dbIndex.tableName}];`,
203
- });
204
- }
205
- }
206
-
207
- // eslint-disable-next-line require-atomic-updates
208
- for (const prjIndex of projectIndexArray) {
209
- const dbIndex = dbIndexArray.find(x => x.tableName === prjIndex.tableName && x.indexName === prjIndex.indexName);
210
- if (dbIndex == null || jsonNormalizeIndex(prjIndex) != jsonNormalizeIndex(dbIndex)) {
211
- try {
212
- await executeAndLog(
213
- options,
214
- `Creating index ${prjIndex.indexName} on ${prjIndex.tableName}`,
215
- getCreateIndexSql(prjIndex)
216
- );
217
- } catch (e) {
218
- if (prjIndex.continueOnError) {
219
- console.log(`FAILED creating index ${prjIndex.indexName}: ${e.message}`);
220
- console.log('Continue because of continueOnError');
221
- } else {
222
- throw e;
223
- }
224
- }
225
- }
226
- }
227
- }
228
-
229
- async function detectTablesOnlyInDb(options) {
230
- const projectTables = options.projectStructure.tables;
231
- const dbTables = options.databaseStructure.mssqlModel.tables;
232
- const { suggestions } = options;
233
-
234
- const removed = _.difference(Object.keys(dbTables), Object.keys(projectTables));
235
- removed.forEach(table => {
236
- suggestions.push({
237
- message: `Table ${table} is only in DB (missing in project)`,
238
- sql: `DROP TABLE [${table}];`,
239
- });
240
- });
241
- }
242
-
243
- async function detectColumnsOnlyInDb(options) {
244
- const projectTables = options.projectStructure.tables;
245
- const dbTables = options.databaseStructure.mssqlModel.tables;
246
- const { suggestions } = options;
247
-
248
- const bothTables = _.intersection(Object.keys(projectTables), Object.keys(dbTables));
249
- for (const tableName of bothTables) {
250
- const dbTable = dbTables[tableName];
251
- const projectTable = projectTables[tableName];
252
-
253
- const removed = _.difference(
254
- dbTable.map(x => x.columnName),
255
- projectTable.columns.map(x => x.name)
256
- );
257
- suggestions.push(
258
- ...removed.map(col => ({
259
- message: `Column ${col} from table ${tableName} is only in DB (missing in project)`,
260
- sql: `ALTER TABLE [${tableName}] DROP COLUMN [${col}];`,
261
- }))
262
- );
263
- }
264
- }
265
-
266
- async function processObjects(
267
- options,
268
- dbObjects,
269
- projectObjects,
270
- objectTypeName,
271
- createRegex,
272
- alterCommand,
273
- sortObjects
274
- ) {
275
- const addedObjects = _.difference(Object.keys(projectObjects), Object.keys(dbObjects));
276
- const bothObjects = _.intersection(Object.keys(projectObjects), Object.keys(dbObjects));
277
-
278
- const addedSorted = sortObjects ? sortObjects(addedObjects, projectObjects) : addedObjects;
279
-
280
- for (const addedObject of addedSorted) {
281
- await executeAndLog(options, `Creating ${objectTypeName} ${addedObject}`, projectObjects[addedObject]);
282
- }
283
- for (const objectName of bothObjects) {
284
- if (dbObjects[objectName].replace(createRegex, '') == projectObjects[objectName].replace(createRegex, '')) continue;
285
- const sql = projectObjects[objectName].replace(createRegex, alterCommand);
286
- await executeAndLog(options, `Altering ${objectTypeName} ${objectName}`, sql);
287
- }
288
- }
289
-
290
- async function deploy(options) {
291
- options.suggestions = [];
292
-
293
- await processAddedTables(options);
294
- await processAddedColumns(options);
295
- await processTableData(options);
296
- await processColumnTypeUpdate(options);
297
- await addMissingReferences(options);
298
- await processIndexes(options);
299
- await detectTablesOnlyInDb(options);
300
- await detectColumnsOnlyInDb(options);
301
- await processObjects(
302
- options,
303
- options.databaseStructure.views,
304
- options.projectStructure.views,
305
- 'view',
306
- /create\s+view/i,
307
- 'ALTER VIEW',
308
- sortViewsByDependency
309
- );
310
- await processObjects(
311
- options,
312
- options.databaseStructure.procedures,
313
- options.projectStructure.procedures,
314
- 'procedure',
315
- /create\s+procedure/i,
316
- 'ALTER PROCEDURE'
317
- );
318
- await processObjects(
319
- options,
320
- options.databaseStructure.functions,
321
- options.projectStructure.functions,
322
- 'function',
323
- /create\s+function/i,
324
- 'ALTER FUNCTION'
325
- );
326
-
327
- if (options.suggestions.length > 0) {
328
- console.log(`Suggestions: ${options.suggestions.length}`);
329
- for (const { message } of options.suggestions) {
330
- console.log(message);
331
- }
332
-
333
- console.log('-------------------------------------------------------------');
334
- for (const { sql } of options.suggestions) {
335
- console.log(sql);
336
- console.log('GO');
337
- }
338
- }
339
-
340
- return options;
341
- }
342
-
343
- module.exports = deploy;
@@ -1,140 +0,0 @@
1
- const _ = require('lodash');
2
- const toposort = require('toposort');
3
-
4
- function getColumnDefinitionSql(tabledef, column, allowDefault = false) {
5
- const dataType = column.type && column.type.toLowerCase() == 'json' ? 'nvarchar(max)' : column.type;
6
- return (
7
- `[${column.name}] ${dataType}${column.length ? '(' + (column.length < 0 ? 'MAX' : column.length) + ')' : ''} ` +
8
- `${column.autoIncrement ? 'IDENTITY' : ''} ${column.notNull ? 'NOT NULL' : 'NULL'}` +
9
- (allowDefault && column.default !== undefined
10
- ? ` CONSTRAINT [DF_${tabledef.name}_${column.name}] DEFAULT ${column.default} `
11
- : '')
12
- );
13
- }
14
-
15
- function getCreateTableSql(tabledef) {
16
- if (!tabledef.primaryKey) {
17
- throw new Error(`Missing primary key in table ${tabledef.name}`);
18
- }
19
-
20
- const deflines = [
21
- ...tabledef.columns.map(column => getColumnDefinitionSql(tabledef, column, true)),
22
- `CONSTRAINT PK_${tabledef.name} PRIMARY KEY (${tabledef.primaryKey.map(x => `[${x}]`).join(',')})`,
23
- ];
24
- return `CREATE TABLE [${tabledef.name}] (\n${deflines.map(x => ' ' + x).join(',\n')}\n);\n`;
25
- }
26
-
27
- function getCreateColumnSql(tabledef, column) {
28
- if (column.notNull && column.default !== undefined) {
29
- const nullColumn = { ...column, notNull: false };
30
- return [
31
- `ALTER TABLE [${tabledef.name}] ADD ${getColumnDefinitionSql(tabledef, nullColumn)}`,
32
- `ALTER TABLE [${tabledef.name}] ADD CONSTRAINT [DF_${tabledef.name}_${column.name}] DEFAULT` +
33
- ` ${column.default} FOR [${column.name}]`,
34
- `UPDATE [${tabledef.name}] SET [${column.name}]=${column.default}`,
35
- `ALTER TABLE [${tabledef.name}] ALTER COLUMN ${getColumnDefinitionSql(tabledef, column)}`,
36
- ];
37
- }
38
- return `ALTER TABLE [${tabledef.name}] ADD ${getColumnDefinitionSql(tabledef, column)}`;
39
- }
40
-
41
- function getCreateFkSql(tabledef, column, projectTables) {
42
- const references = column.references;
43
- const idcol = (projectTables[references] && projectTables[references].primaryKey[0]) || 'id';
44
- return `ALTER TABLE [${tabledef.name}] ADD CONSTRAINT [FK_${tabledef.name}_${column.name}] FOREIGN KEY ([${column.name}]) REFERENCES [${references}]([${idcol}])`;
45
- }
46
-
47
- function getCreateIndexSql(prjIndex) {
48
- return `CREATE ${prjIndex.isUnique ? 'UNIQUE' : ''} INDEX [${prjIndex.indexName}] ON [${
49
- prjIndex.tableName
50
- }] (${prjIndex.columns.map(x => `[${x.columnName}]`).join(',')}) ${
51
- prjIndex.filterDefinition ? `WHERE ${prjIndex.filterDefinition}` : ''
52
- }`;
53
- }
54
-
55
- function getProjectIndexesAsDatabase(projectTables) {
56
- const projectIndexArray = _.flatten(
57
- _.values(
58
- _.mapValues(projectTables, table =>
59
- (table.indexes || []).map(index => ({
60
- indexName: index.name,
61
- isUnique: index.unique || false,
62
- filterDefinition: index.filter,
63
- continueOnError: index.continueOnError,
64
- tableName: table.name,
65
- columns: index.columns.map(col => ({
66
- columnName: col,
67
- isIncludedColumn: false,
68
- })),
69
- }))
70
- )
71
- )
72
- );
73
- return projectIndexArray;
74
- }
75
-
76
- function sortViewsByDependency(viewNames, viewDict) {
77
- const edges = [];
78
- for (const viewName of viewNames) {
79
- edges.push([viewName, null]);
80
- const viewText = viewDict[viewName];
81
- for (const otherView of viewNames) {
82
- if (otherView === viewName) continue;
83
- if ((' ' + viewText + ' ').match('[\\W]' + otherView + '[\\W]')) {
84
- edges.push([otherView, viewName]);
85
- }
86
- }
87
- }
88
- return _.compact(toposort(edges));
89
- }
90
-
91
- function getSqlExpression(data) {
92
- if (data == null) return 'NULL';
93
- if (data === false) return '0';
94
- if (data === true) return '1';
95
- if (_.isNumber(data)) return data.toString();
96
- return `'${data.replace(/'/g, "''")}'`;
97
- }
98
-
99
- function getFillTableSql(table) {
100
- const keyCols = table.insertKey || table.primaryKey;
101
- if (!keyCols) return null;
102
- if (!table.data) return null;
103
- const sql = table.data
104
- .map(row => {
105
- const keyCond = keyCols.map(col => `[${table.name}].[${col}]=${getSqlExpression(row[col])}`).join(' AND ');
106
- const rowCols = Object.keys(row);
107
- const notKeyCols = _.difference(rowCols, keyCols);
108
- const updateCmd = notKeyCols.map(col => `[${col}]=${getSqlExpression(row[col])}`).join(',');
109
- const rowColsCmd = rowCols.map(col => `[${col}]`).join(',');
110
- const rowValuesCmd = rowCols.map(col => `${getSqlExpression(row[col])}`).join(',');
111
- const cmd =
112
- `IF (EXISTS(SELECT * FROM [${table.name}]` +
113
- ` WHERE ${keyCond})) UPDATE [${table.name}]` +
114
- ` SET ${updateCmd} WHERE ${keyCond}` +
115
- ` ELSE INSERT INTO [${table.name}]` +
116
- ` (${rowColsCmd}) VALUES (${rowValuesCmd});\n`;
117
- return cmd;
118
- })
119
- .join('');
120
- if (!sql) return null;
121
-
122
- const identityColumn = table.columns.find(col => col.autoIncrement);
123
- const sqlWithSetup =
124
- identityColumn && keyCols.includes(identityColumn.name)
125
- ? `SET IDENTITY_INSERT [${table.name}] ON;\n${sql}SET IDENTITY_INSERT [${table.name}] OFF;`
126
- : sql;
127
-
128
- return sqlWithSetup;
129
- }
130
-
131
- module.exports = {
132
- getColumnDefinitionSql,
133
- getCreateTableSql,
134
- getCreateColumnSql,
135
- getCreateFkSql,
136
- getCreateIndexSql,
137
- getProjectIndexesAsDatabase,
138
- getFillTableSql,
139
- sortViewsByDependency,
140
- };