pg-mvc-service 2.0.43 → 2.0.44

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.
@@ -0,0 +1,369 @@
1
+ import { TableModel } from "./TableModel";
2
+ import { TColumn } from "./Type";
3
+
4
+ export const createTableDoc = (models: Array<TableModel>, serviceName?: string) => {
5
+ let html = `
6
+ <!DOCTYPE html>
7
+ <html lang="ja">
8
+ <head>
9
+ <meta charset="UTF-8">
10
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
11
+ <link rel="icon" href="assets/favicon.ico" type="image/x-icon">
12
+ <title>table document</title>
13
+ </head>
14
+ <style>
15
+ :root {
16
+ --primary: rgb(73, 204, 144);
17
+ --primary-dark: rgb(64, 169, 121);
18
+ --bg-primary: rgba(73, 204, 144, 0.15);
19
+ --border-primary: rgba(73, 204, 144, 0.3);
20
+ --border-gray: rgb(200, 200, 200);
21
+ }
22
+
23
+ body {
24
+ padding: 0px;
25
+ padding-left: 12px;
26
+ padding-right: 12px;
27
+ margin: 0px;
28
+ color: rgb(30, 35, 40);
29
+ }
30
+
31
+
32
+ button {
33
+ padding-left: 8px;
34
+ padding-right: 8px;
35
+ padding-top: 2px;
36
+ padding-bottom: 2px;
37
+ background-color: var(--primary);
38
+ border: 0px;
39
+ color: #ffffff;
40
+ border-radius: 999px;
41
+ }
42
+
43
+ button:hover {
44
+ background-color: var(--primary-dark);
45
+ }
46
+
47
+ /* title*/
48
+ h1 {
49
+ font-size: 28px;
50
+ font-weight: bold;
51
+ margin-top: 16px;
52
+ margin-bottom: 16px;
53
+ }
54
+
55
+ /* db-title*/
56
+ h2 {
57
+ background-color: var(--primary);
58
+ border-top-left-radius: 8px;
59
+ border-top-right-radius: 8px;
60
+ color: #ffffff;
61
+ padding-left: 4px;
62
+ margin: 0;
63
+ font-size: 24px;
64
+ font-weight: bold;
65
+ }
66
+
67
+ .db-wrapper {
68
+ border-radius: 8px;
69
+ border: var(--primary) solid 1px;
70
+ margin-bottom: 24px;
71
+ }
72
+
73
+ /* table-title*/
74
+ h3 {
75
+ font-size: 18px;
76
+ font-weight: bold;
77
+ }
78
+
79
+ .table-wrapper {
80
+ padding: 0px;
81
+ margin-bottom: 64px;
82
+ }
83
+
84
+ .table-title-wrapper {
85
+ background-color: var(--bg-primary);
86
+ border-top: var(--border-primary) solid 1px;
87
+ margin: 0;
88
+ padding: 2px 4px;
89
+ align-items: center;
90
+ display: flex;
91
+ }
92
+
93
+ .table-title-left {
94
+ font-size: 18px;
95
+ font-weight: bold;
96
+ text-align: left;
97
+ font-size: 18px;
98
+ font-weight: bold;
99
+ }
100
+
101
+ .table-title-right {
102
+ margin-left: auto;
103
+ padding: 2px;
104
+ }
105
+
106
+ .comment-wrapper {
107
+ padding-left: 4px;
108
+ padding-top: 4px;
109
+ padding-bottom: 8px;
110
+ font-size: 14px;
111
+ }
112
+
113
+ table {
114
+ border-collapse: collapse;
115
+ margin-top: 0px;
116
+ margin-left: 8px;
117
+ margin-right: 8px;
118
+ margin-bottom: 12px;
119
+ font-size: 14px;
120
+ }
121
+
122
+ tr:nth-child(odd) {
123
+ background-color: var(--bg-primary); /* 奇数行の背景色を変更 */
124
+ }
125
+
126
+ tr:nth-child(even) {
127
+ background-color: #ffffff; /* 偶数行の背景色を変更 */
128
+ }
129
+
130
+ th {
131
+ padding-left: 4px;
132
+ padding-right: 4px;
133
+ background-color: var(--primary);
134
+ color: #ffffff;
135
+ border: 1px solid var(--border-gray); /* 線の色と太さを指定 */
136
+ }
137
+
138
+ td {
139
+ border: 1px solid var(--border-primary); /* 線の色と太さを指定 */
140
+ padding-left: 4px;
141
+ padding-right: 4px;
142
+ }
143
+
144
+ /* No */
145
+ td:nth-child(1) {
146
+ width: 16px;
147
+ text-align: center;
148
+ }
149
+
150
+ /* PK */
151
+ td:nth-child(2) {
152
+ width: 24px;
153
+ text-align: center;
154
+ }
155
+
156
+ /* name */
157
+ td:nth-child(3) {
158
+ width: 140px;
159
+ }
160
+
161
+ /* alias */
162
+ td:nth-child(4) {
163
+ width: 180px;
164
+ }
165
+
166
+ /* type */
167
+ td:nth-child(5) {
168
+ width: 60px;
169
+ }
170
+
171
+ /* length */
172
+ td:nth-child(6) {
173
+ width: 40px;
174
+ }
175
+
176
+ /* nullable */
177
+ td:nth-child(7) {
178
+ width: 40px;
179
+ }
180
+
181
+ /* default */
182
+ td:nth-child(8) {
183
+ width: 120px;
184
+ }
185
+
186
+ /* Foreign Key */
187
+ td:nth-child(9) {
188
+ width: 300px;
189
+ }
190
+
191
+ /* comment */
192
+ td:nth-child(10) {
193
+ width: auto;
194
+ }
195
+
196
+ /* function */
197
+ td:nth-child(11) {
198
+ width: auto;
199
+ }
200
+ </style>
201
+
202
+ <body>
203
+ <h1>${serviceName === undefined ? '': serviceName + ' :'}Your Table Definition Document</h1>
204
+ `;
205
+
206
+ const dbObj: {[key: string]: Array<TableModel>} = {};
207
+ for (const model of models) {
208
+ if (model.DbName in dbObj === false) {
209
+ dbObj[model.DbName] = [];
210
+ }
211
+ dbObj[model.DbName].push(model);
212
+ }
213
+
214
+ const jsCripFuncs: { [key: string]: string } = {};
215
+ for (const [keyDbName, models] of Object.entries(dbObj)) {
216
+ html += `
217
+ <div class="db-wrapper">
218
+ <h2>${keyDbName} Database</h2>`;
219
+
220
+ for (const model of models) {
221
+ const createFuncName = `clipboard_createTable_${model.DbName}_${model.TableName}`;
222
+ html += `
223
+ <div class="table-wrapper">
224
+ <div class="table-title-wrapper">
225
+ <div class="table-title-left">${model.Id !== "" ? `[${model.Id}] ` : ""}${model.TableName} ${model.TableDescription !== '' ? ` : ${model.TableDescription}` : ''}</div>
226
+ <button class="table-title-right" onclick="${createFuncName}()">Copy Create Query</button>
227
+ </div>
228
+ <div class="comment-wrapper">${model.Comment.replace('\n', '<br>')}</div>
229
+
230
+ <table>
231
+ <tr>
232
+ <th>No</th>
233
+ <th>PK</th>
234
+ <th>name</th>
235
+ <th>alias</th>
236
+ <th>type</th>
237
+ <th>length</th>
238
+ <th>nullable</th>
239
+ <th>default</th>
240
+ <th>foreign key</th>
241
+ <th>comment</th>
242
+ <th>function</th>
243
+ </tr>`;
244
+
245
+ const createColExpressions: Array<string> = [];
246
+ const pkColNames: Array<string> = [];
247
+ let index = 0;
248
+ for (const [keyColName, column] of Object.entries(model.Columns)) {
249
+ index++;
250
+ const addFuncName = `clipboard_addColumn_${model.DbName}_${model.TableName}_${keyColName}`;
251
+ const dropFuncName = `clipboard_dropColumn_${model.DbName}_${model.TableName}_${keyColName}`;
252
+
253
+ // 外部キー用
254
+ let references: Array<string> = [];
255
+ for (const ref of model.GetReferences(keyColName)) {
256
+ const targetRef = ref.columns.filter(col => col.target === keyColName);
257
+ if (targetRef.length > 0) {
258
+ references.push(`[${ref.table}].[${targetRef[0].ref}]`);
259
+ }
260
+ }
261
+ references = Array.from(new Set(references)); // 重複を除く
262
+
263
+ html += `
264
+ <tr>
265
+ <td>${index}</td>
266
+ <td>${column.attribute === 'primary' ? 'PK' : ''}</td>
267
+ <td>${keyColName}</td>
268
+ <td>${column.alias ?? keyColName}</td>
269
+ <td>${column.type}</td>
270
+ <td>${column.length ?? ''}</td>
271
+ <td>${column.attribute === 'nullable' ? 'nullable' : ''}</td>
272
+ <td>${column.attribute === 'hasDefault' ? column.default ?? '???' : ''}</td>
273
+ <td>${references.length === 0 ? '' : references.join('<br>')}</td>
274
+ <td>${(column.comment ?? '').replace('\n', '<br>')}</td>
275
+ <td>
276
+ ${column.attribute === "primary" ? `` : `
277
+ <button onclick="${addFuncName}()">Copy add column</button><br>
278
+ <button onclick="${dropFuncName}()">Copy drop column</button>
279
+ `}
280
+ </td>
281
+ </tr>`;
282
+
283
+ jsCripFuncs[addFuncName] = `ALTER TABLE ${model.TableName} ADD COLUMN ${keyColName} ${toColumnType(column)} ${toColumnAttibute(column)};`;
284
+ jsCripFuncs[dropFuncName] = `ALTER TABLE ${model.TableName} DROP COLUMN ${keyColName};`;
285
+
286
+ // CreateTable作成用
287
+ createColExpressions.push(`${keyColName} ${toColumnType(column)} ${toColumnAttibute(column)}`)
288
+ if (column.attribute === 'primary') {
289
+ pkColNames.push(keyColName);
290
+ }
291
+ }
292
+
293
+ // CreateTable作成文
294
+ const expressions = [...createColExpressions];
295
+ if (pkColNames.length > 0) {
296
+ expressions.push(`PRIMARY KEY (${pkColNames.join(', ')})`);
297
+ }
298
+ for (const ref of model.References) {
299
+ expressions.push(`FOREIGN KEY (${ref.columns.map(col => col.target).join(', ')}) REFERENCES ${ref.table}(${ref.columns.map(col => col.ref).join(', ')})`);
300
+ }
301
+ jsCripFuncs[createFuncName] = `CREATE TABLE ${model.TableName} (\n ${expressions.join(',\n ')}\n);`;
302
+
303
+ html += `
304
+ </table>
305
+ </div>`;
306
+ }
307
+ html += `
308
+ </div>`;
309
+ }
310
+
311
+ html += `\n <script>\n`;
312
+ for (const [keyFunName, value] of Object.entries(jsCripFuncs)) {
313
+ html += `
314
+ function ${keyFunName}() {
315
+ const el = document.createElement('textarea');
316
+ el.value = \`${value}\`;
317
+ document.body.appendChild(el);
318
+ el.select();
319
+ document.execCommand('copy');
320
+ document.body.removeChild(el);
321
+ alert('コピーしました');
322
+ }\n`;
323
+ }
324
+
325
+ html += ` </script>
326
+ </body>
327
+ </html>
328
+ `;
329
+ return html;
330
+ }
331
+
332
+ function toColumnType(column: TColumn) {
333
+ if (column.type.startsWith('uuid')) {
334
+ return column.type.replace('uuid', 'UUID');
335
+ } else if (column.type.startsWith('bool')) {
336
+ return column.type.replace('bool', 'BOOLEAN');
337
+ } else if (column.type.startsWith('date')) {
338
+ return column.type.replace('date', 'DATE');
339
+ } else if (column.type.startsWith('integer')) {
340
+ return column.type.replace('integer', 'INTEGER');
341
+ } else if (column.type.startsWith('real')) {
342
+ return column.type.replace('real', 'REAL');
343
+ } else if (column.type.startsWith('string')) {
344
+ return column.type.replace('string', `VARCHAR(${column.length})`);
345
+ } else if (column.type.startsWith('timestamp')) {
346
+ return column.type.replace('timestamp', 'TIMESTAMP');
347
+ } else if (column.type.startsWith('time')) {
348
+ return column.type.replace('time', 'TIME');
349
+ } else if (column.type.startsWith('jsonb')) {
350
+ return column.type.replace('jsonb', 'JSONB');
351
+ } else if (column.type.startsWith('json')) {
352
+ return column.type.replace('json', 'JSON');
353
+ }
354
+
355
+ return '';
356
+ }
357
+
358
+ function toColumnAttibute(column: TColumn) {
359
+ switch (column.attribute) {
360
+ case 'hasDefault':
361
+ return 'NOT NULL DEFAULT ' + column.default;
362
+ case 'noDefault':
363
+ return 'NOT NULL';
364
+ case 'nullable':
365
+ return 'NULL';
366
+ case 'primary':
367
+ return ''; // 主キーは後で設定するので
368
+ }
369
+ }