@agung_dhewe/webapps 1.1.2
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/LICENSE +28 -0
- package/README.md +2 -0
- package/jsconfig.json +10 -0
- package/libs/fgta5js-dist/fgta5js-v1.8.3.min.css +2 -0
- package/libs/fgta5js-dist/fgta5js-v1.8.3.min.js +11 -0
- package/libs/fgta5js-dist/fgta5js-v1.8.3.min.js.map +1 -0
- package/libs/fgta5js-dist/fonts/karla-italic-latin-ext.woff2 +0 -0
- package/libs/fgta5js-dist/fonts/karla-italic-latin.woff2 +0 -0
- package/libs/fgta5js-dist/fonts/karla-normal-latin-ext.woff2 +0 -0
- package/libs/fgta5js-dist/fonts/karla-normal-latin.woff2 +0 -0
- package/libs/fgta5js-dist/fonts/karla.css +142 -0
- package/libs/webmodule/module-edit.css +163 -0
- package/libs/webmodule/module-footer.css +22 -0
- package/libs/webmodule/module-list.css +25 -0
- package/libs/webmodule/module.css +52 -0
- package/libs/webmodule/module.js +195 -0
- package/libs/webmodule/pagehelper.mjs +45 -0
- package/modules/generator/appgen-components.mjs +142 -0
- package/modules/generator/appgen-icons.mjs +6 -0
- package/modules/generator/appgen-io.mjs +784 -0
- package/modules/generator/appgen-ui-search.mjs +173 -0
- package/modules/generator/appgen-ui-unique.mjs +153 -0
- package/modules/generator/appgen-ui.mjs +1181 -0
- package/modules/generator/generator-context.mjs +18 -0
- package/modules/generator/generator-designtemplate.html +1508 -0
- package/modules/generator/generator-ext.html +0 -0
- package/modules/generator/generator-ext.mjs +3 -0
- package/modules/generator/generator.css +642 -0
- package/modules/generator/generator.mjs +195 -0
- package/modules/generator/generator.png +0 -0
- package/modules/generator/generatorEdit.html +185 -0
- package/modules/generator/generatorEdit.mjs +238 -0
- package/modules/generator/generatorList.html +32 -0
- package/modules/generator/generatorList.mjs +243 -0
- package/modules/login/login.css +11 -0
- package/modules/login/login.html +12 -0
- package/modules/login/login.mjs +111 -0
- package/package.json +46 -0
- package/percobaan/simmpan-ke-minio.js +24 -0
- package/src/api.js +80 -0
- package/src/apis/generator.api.js +226 -0
- package/src/apis/login.api.js +109 -0
- package/src/bucket.js +24 -0
- package/src/context.js +26 -0
- package/src/datalog.sql +22 -0
- package/src/datarecords.js +0 -0
- package/src/db.js +61 -0
- package/src/generator/createApiExtenderModule.js +54 -0
- package/src/generator/createApiModule.js +218 -0
- package/src/generator/createIcon.js +62 -0
- package/src/generator/createInfoAboutExtender.js +42 -0
- package/src/generator/createInfoLogs.js +41 -0
- package/src/generator/createInfoRecordExtender.js +41 -0
- package/src/generator/createModuleContext.js +48 -0
- package/src/generator/createModuleDetilEditHtml.js +110 -0
- package/src/generator/createModuleDetilEditMjs.js +172 -0
- package/src/generator/createModuleDetilListHtml.js +146 -0
- package/src/generator/createModuleDetilListMjs.js +73 -0
- package/src/generator/createModuleEjs.js +51 -0
- package/src/generator/createModuleExtenderHtml.js +43 -0
- package/src/generator/createModuleExtenderMjs.js +43 -0
- package/src/generator/createModuleHeaderEditHtml.js +148 -0
- package/src/generator/createModuleHeaderEditMjs.js +197 -0
- package/src/generator/createModuleHeaderListHtml.js +144 -0
- package/src/generator/createModuleHeaderListMjs.js +67 -0
- package/src/generator/createModuleMjs.js +67 -0
- package/src/generator/createModuleRollup.js +42 -0
- package/src/generator/createProgramData.js +96 -0
- package/src/generator/createTable.js +156 -0
- package/src/generator/ddl.js +475 -0
- package/src/generator/helper.js +149 -0
- package/src/generator/templates/__rollup-module.ejs +90 -0
- package/src/generator/templates/api-extender-module.js.ejs +0 -0
- package/src/generator/templates/api-module.js.ejs +818 -0
- package/src/generator/templates/module-context.ejs +16 -0
- package/src/generator/templates/module-ext-about.ejs +1 -0
- package/src/generator/templates/module-ext-record.ejs +1 -0
- package/src/generator/templates/module-ext.html.ejs +3 -0
- package/src/generator/templates/module-ext.mjs.ejs +21 -0
- package/src/generator/templates/module-logs.ejs +14 -0
- package/src/generator/templates/module.ejs.ejs +48 -0
- package/src/generator/templates/module.mjs.ejs +256 -0
- package/src/generator/templates/moduleDetilEdit.html.ejs +34 -0
- package/src/generator/templates/moduleDetilEdit.mjs.ejs +792 -0
- package/src/generator/templates/moduleDetilList.html.ejs +26 -0
- package/src/generator/templates/moduleDetilList.mjs.ejs +319 -0
- package/src/generator/templates/moduleHeaderEdit.html.ejs +53 -0
- package/src/generator/templates/moduleHeaderEdit.mjs.ejs +807 -0
- package/src/generator/templates/moduleHeaderList.html.ejs +24 -0
- package/src/generator/templates/moduleHeaderList.mjs.ejs +308 -0
- package/src/generator/templates/sqlAddField.ejs +3 -0
- package/src/generator/templates/sqlAddForeignKey.ejs +12 -0
- package/src/generator/templates/sqlAddUniqueIndex.ejs +4 -0
- package/src/generator/templates/sqlCreateTable.ejs +9 -0
- package/src/generator/templates/sqlDropForeignKey.ejs +3 -0
- package/src/generator/templates/sqlDropUniqueIndex.ejs +4 -0
- package/src/generator/templates/sqlModifyField.ejs +6 -0
- package/src/generator/trygenerate.js +83 -0
- package/src/generator/worker.js +389 -0
- package/src/helper.js +82 -0
- package/src/logger.js +39 -0
- package/src/router.js +84 -0
- package/src/routers/defaultLoginApi.js +29 -0
- package/src/routers/defaultLoginAsset.js +18 -0
- package/src/routers/defaultLoginPage.js +36 -0
- package/src/routers/defaultRootIndex.js +16 -0
- package/src/routers/downloadHandler.js +51 -0
- package/src/routers/fileUploadApi.js +15 -0
- package/src/routers/generatorApi.js +30 -0
- package/src/routers/generatorAsset.js +18 -0
- package/src/routers/generatorPage.js +37 -0
- package/src/routers/handleError.js +43 -0
- package/src/routers/handleModuleNotfound.js +12 -0
- package/src/routers/moduleApi.js +34 -0
- package/src/routers/modulePage.js +102 -0
- package/src/sequencerdoc.js +311 -0
- package/src/sequencerline.js +214 -0
- package/src/session.js +57 -0
- package/src/startup.js +59 -0
- package/src/webapps.js +239 -0
- package/src/workermanager.js +83 -0
- package/templates/_lib_debug.ejs +11 -0
- package/templates/_lib_production.ejs +5 -0
- package/templates/application.page.ejs +143 -0
- package/templates/generator.page.ejs +131 -0
- package/templates/index.page.ejs +24 -0
- package/templates/login.page.ejs +102 -0
- package/templates/moduleError.ejs +16 -0
- package/templates/moduleNotfound.ejs +14 -0
- package/webapps.code-workspace +11 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { kebabToCamel, isFileExist, getSectionData } from './helper.js'
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
import * as ddl from './ddl.js'
|
|
4
|
+
import path from 'path'
|
|
5
|
+
import fs from 'fs/promises'
|
|
6
|
+
import pgp from 'pg-promise'
|
|
7
|
+
import db from '../db.js'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = path.dirname(__filename);
|
|
12
|
+
|
|
13
|
+
export async function createTable(context, options) {
|
|
14
|
+
const skipGenerate = options.skipGenerate===true
|
|
15
|
+
const moduleName = context.moduleName
|
|
16
|
+
const title = context.title
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
if (skipGenerate) {
|
|
22
|
+
context.postMessage({message: `skip generate table(s)`})
|
|
23
|
+
return
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
// start geneate program code
|
|
28
|
+
let sections = []
|
|
29
|
+
for (var entityName in context.entities) {
|
|
30
|
+
|
|
31
|
+
// prepare target file
|
|
32
|
+
const targetFile = path.join(context.moduleDir, `${moduleName}-${entityName}.sql`)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
// reporting progress to parent process
|
|
36
|
+
context.postMessage({message: `generating file: '${targetFile}`})
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
// start generate table for tis entity
|
|
40
|
+
const entity = context.entities[entityName]
|
|
41
|
+
const {table, descr, pk, identifierMethod} = entity
|
|
42
|
+
const pkData = entity.Items[pk]
|
|
43
|
+
const {schema, tablename} = ddl.parseTableName(table)
|
|
44
|
+
const {data_fieldname, data_type, data_length, description} = pkData
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
const scriptContent = []
|
|
49
|
+
|
|
50
|
+
scriptContent.push(`-- ${moduleName}.sql`)
|
|
51
|
+
scriptContent.push("\n")
|
|
52
|
+
|
|
53
|
+
// Buat Table dengan field hanya untuk primary key
|
|
54
|
+
{
|
|
55
|
+
const sql = await ddl.createTable(schema, tablename, descr, {
|
|
56
|
+
fieldname: data_fieldname,
|
|
57
|
+
datatype: data_type,
|
|
58
|
+
length: data_length,
|
|
59
|
+
identifierMethod: identifierMethod
|
|
60
|
+
})
|
|
61
|
+
scriptContent.push(sql)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const recordColumns = createRecordColumns()
|
|
65
|
+
const entityItems = structuredClone({...entity.Items, ...recordColumns})
|
|
66
|
+
|
|
67
|
+
// Buat Fields
|
|
68
|
+
{
|
|
69
|
+
|
|
70
|
+
for (var fieldname in entityItems) {
|
|
71
|
+
if (fieldname==pk) {
|
|
72
|
+
continue
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const field = entityItems[fieldname]
|
|
76
|
+
const {data_fieldname, data_type, data_length, data_precision, data_allownull, data_defaultvalue, description} = field
|
|
77
|
+
|
|
78
|
+
const sql = await ddl.createField(schema, tablename, {
|
|
79
|
+
fieldname: data_fieldname,
|
|
80
|
+
datatype: data_type,
|
|
81
|
+
length: data_length,
|
|
82
|
+
precision: data_precision,
|
|
83
|
+
allownull: data_allownull,
|
|
84
|
+
defaultvalue: data_defaultvalue,
|
|
85
|
+
description: description
|
|
86
|
+
})
|
|
87
|
+
scriptContent.push(sql)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// buat foreign key
|
|
93
|
+
scriptContent.push("\n")
|
|
94
|
+
{
|
|
95
|
+
const foreignKeys = Object.entries(entityItems)
|
|
96
|
+
.filter(([_, value]) => value.Reference.table !== null && value.Reference.table !== '')
|
|
97
|
+
.reduce((acc, [key, value]) => {
|
|
98
|
+
acc[key] = value;
|
|
99
|
+
return acc;
|
|
100
|
+
}, {})
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
const sql = await ddl.createFereignKey(schema, tablename, foreignKeys)
|
|
104
|
+
scriptContent.push(sql)
|
|
105
|
+
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
// buat unique index
|
|
111
|
+
scriptContent.push("\n")
|
|
112
|
+
{
|
|
113
|
+
const sql = await ddl.createUniqueIndex(schema, tablename, entity.Uniques)
|
|
114
|
+
scriptContent.push(sql)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
let content = scriptContent.join("\n")
|
|
119
|
+
await fs.writeFile(targetFile, content, 'utf8');
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
}
|
|
123
|
+
} catch (err) {
|
|
124
|
+
throw err
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
function createRecordColumns() {
|
|
131
|
+
const records = {
|
|
132
|
+
_createby: {
|
|
133
|
+
data_fieldname: '_createby', data_type: 'bigint', data_allownull: false, description: 'user yang pertama kali membuat record ini',
|
|
134
|
+
Reference: {table: '',pk: ''}
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
_createdate: {
|
|
138
|
+
data_fieldname: '_createdate', data_type: 'timestamp', data_allownull: false, description: 'waktu record dibuat pertama kali',
|
|
139
|
+
Reference: {table: '',pk: ''}
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
_modifyby: {
|
|
143
|
+
data_fieldname: '_modifyby', data_type: 'bigint', data_allownull: true, description: 'user yang terakhir modifikasi record ini',
|
|
144
|
+
Reference: {table: '',pk: ''}
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
_modifydate: {
|
|
148
|
+
data_fieldname: '_modifydate', data_type: 'timestamp', data_allownull: true, description: 'waktu terakhir record dimodifikasi',
|
|
149
|
+
Reference: {table: '',pk: ''}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return records
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
|
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
import pgp from 'pg-promise'
|
|
2
|
+
import db from '../db.js'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
import fs from 'fs/promises'
|
|
5
|
+
import ejs from 'ejs'
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
import { console } from 'inspector'
|
|
8
|
+
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = path.dirname(__filename);
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
export function parseTableName(str) {
|
|
14
|
+
if (typeof str !== 'string' || !str.trim()) {
|
|
15
|
+
throw new Error("Input harus berupa string non-kosong");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const parts = str.split('.');
|
|
19
|
+
if (parts.length === 2) {
|
|
20
|
+
const [schema, tablename] = parts;
|
|
21
|
+
return { schema, tablename };
|
|
22
|
+
} else if (parts.length === 1) {
|
|
23
|
+
return { schema: 'public', tablename: parts[0] };
|
|
24
|
+
} else {
|
|
25
|
+
throw new Error("Format tidak valid. Gunakan 'schema.tablename' atau hanya 'tablename'");
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function tableExist(schema, tablename) {
|
|
30
|
+
const sqlCekTableExists = `
|
|
31
|
+
SELECT EXISTS (
|
|
32
|
+
SELECT 1
|
|
33
|
+
FROM information_schema.tables
|
|
34
|
+
WHERE table_schema = \${schema}
|
|
35
|
+
AND table_name = \${tablename}
|
|
36
|
+
) AS "exists"
|
|
37
|
+
`
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
const res = await db.one(sqlCekTableExists, {schema, tablename});
|
|
41
|
+
return res.exists
|
|
42
|
+
} catch (err) {
|
|
43
|
+
throw err
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function fieldExists(schema, tablename, fieldname) {
|
|
48
|
+
const sqlCekFieldExists = `
|
|
49
|
+
SELECT EXISTS (
|
|
50
|
+
SELECT 1
|
|
51
|
+
FROM information_schema.columns
|
|
52
|
+
WHERE table_schema = \${schema}
|
|
53
|
+
AND table_name = \${tablename}
|
|
54
|
+
AND column_name = \${fieldname}
|
|
55
|
+
) AS "exists"
|
|
56
|
+
`
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
const res = await db.one(sqlCekFieldExists, {schema, tablename, fieldname});
|
|
60
|
+
return res.exists
|
|
61
|
+
} catch (err) {
|
|
62
|
+
throw err
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export async function createTable(schema, tablename, tabledescr, pk) {
|
|
67
|
+
const {fieldname, datatype, length, precision, allownull, defaultvalue, description, identifierMethod} = pk
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
|
|
71
|
+
// manual, auto-by-default, auto-always, auto-yearly, auto-monthly, custom
|
|
72
|
+
|
|
73
|
+
let type
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
if (['int', 'bigint'].includes(datatype)) {
|
|
77
|
+
if (datatype=='int') {
|
|
78
|
+
// auto-monthly dan auto-yearly hanya berlaku untuk bigint
|
|
79
|
+
if (['auto-yearly', 'auto-monthly'].includes(identifierMethod)) {
|
|
80
|
+
throw new Error(`identifier '${identifierMethod}' tidak bisa diterapkan untuk tipe data '${datatype}'`)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// if (['auto-yearly', 'auto-monthly'].includes(identifierMethod)) {
|
|
85
|
+
// throw new Error(`identifier '${identifierMethod}' tidak bisa diterapkan untuk tipe data '${datatype}'`)
|
|
86
|
+
// } else
|
|
87
|
+
|
|
88
|
+
if (identifierMethod=='auto-by-default') {
|
|
89
|
+
// auto increment by default apabila tidak diisi
|
|
90
|
+
type = `${datatype} generated by default as identity`
|
|
91
|
+
|
|
92
|
+
} else if (identifierMethod=='auto-always') {
|
|
93
|
+
// auto increment otomatis, tidak bisa diisi sendiri kecuali di ovveride counternya
|
|
94
|
+
type = `${datatype} generated always as identity`
|
|
95
|
+
|
|
96
|
+
} else {
|
|
97
|
+
// manual or custome
|
|
98
|
+
type = `${datatype} not null`
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
} else if (['char', 'varchar', 'text'].includes(datatype)) {
|
|
102
|
+
// manual, auto-by-default, auto-always, auto-yearly, auto-monthly, custom
|
|
103
|
+
if (['auto-by-default', 'auto-always'].includes(identifierMethod)) {
|
|
104
|
+
throw new Error(`identifier '${identifierMethod}' tidak bisa diterapkan untuk tipe data '${datatype}'`)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (type=='text') {
|
|
108
|
+
type = `text not null`
|
|
109
|
+
} else {
|
|
110
|
+
type = `${datatype}(${length}) not null`
|
|
111
|
+
}
|
|
112
|
+
} else if(datatype=='smallint') {
|
|
113
|
+
if (identifierMethod=='auto-by-default') {
|
|
114
|
+
type = `${datatype} generated by default as identity`
|
|
115
|
+
} else if (identifierMethod=='auto-always') {
|
|
116
|
+
throw new Error(`datatype '${datatype}' tidak diperbolehkan untuk menggunakan auto-always`)
|
|
117
|
+
} else {
|
|
118
|
+
type = `${datatype} not null`
|
|
119
|
+
}
|
|
120
|
+
} else {
|
|
121
|
+
throw new Error(`datatype '${datatype}' currently is not supported by generator`)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const variables = {
|
|
125
|
+
schema,
|
|
126
|
+
tablename,
|
|
127
|
+
fieldname,
|
|
128
|
+
type,
|
|
129
|
+
tabledescr
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const tplFilePath = path.join(__dirname, 'templates', 'sqlCreateTable.ejs')
|
|
133
|
+
const template = await fs.readFile(tplFilePath, 'utf-8');
|
|
134
|
+
const sql = ejs.render(template, variables)
|
|
135
|
+
|
|
136
|
+
// eksekusi create table
|
|
137
|
+
if (!await tableExist(schema, tablename)) {
|
|
138
|
+
await db.none(sql)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
return sql
|
|
143
|
+
} catch (err) {
|
|
144
|
+
throw err
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
export async function createField(schema, tablename, field) {
|
|
151
|
+
const {fieldname, datatype, length, precision, allownull, defaultvalue, description} = field
|
|
152
|
+
|
|
153
|
+
const script = []
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
|
|
157
|
+
const type = getSqlDataType(datatype, length, precision)
|
|
158
|
+
const sqlAdd = await sqlAddField(schema, tablename, field)
|
|
159
|
+
const sqlModify = await sqlModifyField(schema, tablename, field)
|
|
160
|
+
|
|
161
|
+
script.push('-- =============================================')
|
|
162
|
+
script.push(`-- FIELD: ${fieldname} ${type}`)
|
|
163
|
+
script.push('-- =============================================')
|
|
164
|
+
script.push(sqlAdd)
|
|
165
|
+
script.push(sqlModify)
|
|
166
|
+
script.push('')
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
if (await fieldExists(schema, tablename, fieldname)) {
|
|
170
|
+
await db.none(sqlModify)
|
|
171
|
+
} else {
|
|
172
|
+
await db.none(sqlAdd)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return script.join("\n")
|
|
176
|
+
} catch (err) {
|
|
177
|
+
throw err
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function getSqlDataType(datatype, length, precision) {
|
|
182
|
+
if (['char', 'varchar'].includes(datatype)) {
|
|
183
|
+
return `${datatype}(${length})`
|
|
184
|
+
} else if (datatype=='decimal') {
|
|
185
|
+
return `${datatype}(${length}, ${precision})`
|
|
186
|
+
} else if (datatype=='timestamp') {
|
|
187
|
+
return 'timestamp with time zone'
|
|
188
|
+
} else {
|
|
189
|
+
return datatype
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function defaultValueOf(datatype, defaultvalue, allownull) {
|
|
194
|
+
if (['char', 'varchar', 'text'].includes(datatype)) {
|
|
195
|
+
if (defaultvalue=='') {
|
|
196
|
+
if (allownull) {
|
|
197
|
+
return null
|
|
198
|
+
} else {
|
|
199
|
+
return `''`
|
|
200
|
+
}
|
|
201
|
+
} else {
|
|
202
|
+
return `'${defaultvalue}'`
|
|
203
|
+
}
|
|
204
|
+
} else if (['int', 'smallint', 'bigint', 'decimal'].includes(datatype)) {
|
|
205
|
+
if (defaultvalue=='') {
|
|
206
|
+
if (allownull) {
|
|
207
|
+
return null
|
|
208
|
+
} else {
|
|
209
|
+
return '0'
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
return defaultvalue
|
|
213
|
+
}
|
|
214
|
+
} else if (['date', 'time', 'timestamp'].includes(datatype)) {
|
|
215
|
+
if (defaultvalue=='') {
|
|
216
|
+
if (allownull) {
|
|
217
|
+
return null
|
|
218
|
+
} else {
|
|
219
|
+
return '(now())'
|
|
220
|
+
}
|
|
221
|
+
} else {
|
|
222
|
+
return defaultvalue
|
|
223
|
+
}
|
|
224
|
+
} else if (datatype=='boolean') {
|
|
225
|
+
if (allownull) {
|
|
226
|
+
return null
|
|
227
|
+
} else {
|
|
228
|
+
if (defaultvalue=='1' || defaultvalue =='true') {
|
|
229
|
+
return true
|
|
230
|
+
} else {
|
|
231
|
+
return false
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
} else {
|
|
235
|
+
return defaultvalue
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
async function sqlAddField(schema, tablename, f) {
|
|
241
|
+
const {fieldname, datatype, length, precision, allownull, defaultvalue, description} = f
|
|
242
|
+
|
|
243
|
+
try {
|
|
244
|
+
|
|
245
|
+
const type = getSqlDataType(datatype, length, precision)
|
|
246
|
+
const setnull = !allownull ? 'not null' : ''
|
|
247
|
+
const value = defaultValueOf(datatype, defaultvalue, allownull)
|
|
248
|
+
const setdefault = value!=null ? `default ${value}` : ''
|
|
249
|
+
const variables = {
|
|
250
|
+
schema,
|
|
251
|
+
tablename,
|
|
252
|
+
fieldname,
|
|
253
|
+
type,
|
|
254
|
+
setnull,
|
|
255
|
+
setdefault,
|
|
256
|
+
description
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const tplFilePath = path.join(__dirname, 'templates', 'sqlAddField.ejs')
|
|
260
|
+
const template = await fs.readFile(tplFilePath, 'utf-8');
|
|
261
|
+
const sql = ejs.render(template, variables)
|
|
262
|
+
return sql
|
|
263
|
+
} catch (err) {
|
|
264
|
+
throw err
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
async function sqlModifyField(schema, tablename, f) {
|
|
269
|
+
const {fieldname, datatype, length, precision, allownull, defaultvalue, description} = f
|
|
270
|
+
|
|
271
|
+
try {
|
|
272
|
+
const type = getSqlDataType(datatype, length, precision)
|
|
273
|
+
const alternull = allownull ? `ALTER COLUMN ${fieldname} DROP NOT NULL` : `ALTER COLUMN ${fieldname} SET NOT NULL`
|
|
274
|
+
const value = defaultValueOf(datatype, defaultvalue, allownull)
|
|
275
|
+
const alterdefault = value==null ? `ALTER COLUMN ${fieldname} DROP DEFAULT` : `ALTER COLUMN ${fieldname} SET DEFAULT ${value}`
|
|
276
|
+
const variables = {
|
|
277
|
+
schema,
|
|
278
|
+
tablename,
|
|
279
|
+
fieldname,
|
|
280
|
+
type,
|
|
281
|
+
alterdefault,
|
|
282
|
+
alternull,
|
|
283
|
+
description
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const tplFilePath = path.join(__dirname, 'templates', 'sqlModifyField.ejs')
|
|
287
|
+
const template = await fs.readFile(tplFilePath, 'utf-8');
|
|
288
|
+
const sql = ejs.render(template, variables)
|
|
289
|
+
return sql
|
|
290
|
+
} catch (err) {
|
|
291
|
+
throw err
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export async function createUniqueIndex(schema, tablename, uniques) {
|
|
296
|
+
const script = []
|
|
297
|
+
|
|
298
|
+
script.push('-- =============================================')
|
|
299
|
+
script.push(`-- UNIQUE INDEX`)
|
|
300
|
+
script.push('-- =============================================')
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
try {
|
|
304
|
+
|
|
305
|
+
// Hapus semua existing unique index
|
|
306
|
+
const sqlGetIniques = `
|
|
307
|
+
SELECT constraint_name
|
|
308
|
+
FROM information_schema.table_constraints
|
|
309
|
+
WHERE constraint_type = 'UNIQUE'
|
|
310
|
+
AND table_schema = \${schema}
|
|
311
|
+
AND table_name = \${tablename};
|
|
312
|
+
`
|
|
313
|
+
const existingUniques = await db.any(sqlGetIniques, {schema:schema, tablename:tablename});
|
|
314
|
+
if (existingUniques.length>0) {
|
|
315
|
+
const variables = {
|
|
316
|
+
schema,
|
|
317
|
+
tablename,
|
|
318
|
+
existingUniques
|
|
319
|
+
}
|
|
320
|
+
const tplFilePath = path.join(__dirname, 'templates', 'sqlDropUniqueIndex.ejs')
|
|
321
|
+
const template = await fs.readFile(tplFilePath, 'utf-8');
|
|
322
|
+
const sqlDropUnique = ejs.render(template, variables)
|
|
323
|
+
|
|
324
|
+
await db.none(sqlDropUnique)
|
|
325
|
+
|
|
326
|
+
script.push(sqlDropUnique)
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
// Tambahkan Unique Index
|
|
332
|
+
const data = []
|
|
333
|
+
for (let uniqName in uniques) {
|
|
334
|
+
let uniq = uniques[uniqName]
|
|
335
|
+
data.push({
|
|
336
|
+
uniquename: `uq$${schema}$${tablename}$${uniq.name}`,
|
|
337
|
+
uniquefields:uniq.fields})
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (data.length>0) {
|
|
341
|
+
const variables = {
|
|
342
|
+
schema,
|
|
343
|
+
tablename,
|
|
344
|
+
data
|
|
345
|
+
}
|
|
346
|
+
const tplFilePath = path.join(__dirname, 'templates', 'sqlAddUniqueIndex.ejs')
|
|
347
|
+
const template = await fs.readFile(tplFilePath, 'utf-8');
|
|
348
|
+
const sqlAddUnique = ejs.render(template, variables)
|
|
349
|
+
|
|
350
|
+
await db.none(sqlAddUnique)
|
|
351
|
+
|
|
352
|
+
script.push(sqlAddUnique)
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
return script.join("\n")
|
|
357
|
+
} catch (err) {
|
|
358
|
+
throw err
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
export async function createFereignKey(schema, tablename, foreignKeys) {
|
|
364
|
+
// const {fk_name, fk_table, fk_field} = reference
|
|
365
|
+
|
|
366
|
+
const script = []
|
|
367
|
+
|
|
368
|
+
script.push('-- =============================================')
|
|
369
|
+
script.push(`-- FOREIGN KEY CONSTRAINT`)
|
|
370
|
+
script.push('-- =============================================')
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
try {
|
|
374
|
+
// Drop dulu referensi yang ada
|
|
375
|
+
{
|
|
376
|
+
const sqlGetFk = `
|
|
377
|
+
SELECT constraint_name
|
|
378
|
+
FROM information_schema.table_constraints
|
|
379
|
+
WHERE constraint_type = 'FOREIGN KEY'
|
|
380
|
+
AND table_schema = \${schema}
|
|
381
|
+
AND table_name = \${tablename}
|
|
382
|
+
`
|
|
383
|
+
const existingFk = await db.any(sqlGetFk, {schema, tablename});
|
|
384
|
+
if (existingFk.length>0) {
|
|
385
|
+
const variables = {
|
|
386
|
+
schema,
|
|
387
|
+
tablename,
|
|
388
|
+
existingFk
|
|
389
|
+
}
|
|
390
|
+
const tplFilePath = path.join(__dirname, 'templates', 'sqlDropForeignKey.ejs')
|
|
391
|
+
const template = await fs.readFile(tplFilePath, 'utf-8');
|
|
392
|
+
const sqlDropForeignKey = ejs.render(template, variables)
|
|
393
|
+
|
|
394
|
+
await db.none(sqlDropForeignKey)
|
|
395
|
+
script.push(sqlDropForeignKey)
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
// Tambahkan kembali foreign key
|
|
401
|
+
{
|
|
402
|
+
const fkList = []
|
|
403
|
+
for (var fieldname in foreignKeys) {
|
|
404
|
+
const field = foreignKeys[fieldname]
|
|
405
|
+
const {data_fieldname, Reference} = field
|
|
406
|
+
const ref_name = `fk$${schema}$${tablename}$${data_fieldname}`
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
{
|
|
410
|
+
const {schema, tablename} = parseTableName(Reference.table)
|
|
411
|
+
Reference.ref_schema = schema
|
|
412
|
+
Reference.ref_tablename = tablename
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
fkList.push({
|
|
416
|
+
fieldname: data_fieldname,
|
|
417
|
+
ref_name: ref_name,
|
|
418
|
+
ref_schema: Reference.ref_schema,
|
|
419
|
+
ref_tablename: Reference.ref_tablename,
|
|
420
|
+
ref_fieldname: Reference.bindingValue
|
|
421
|
+
})
|
|
422
|
+
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const variables = {
|
|
426
|
+
schema,
|
|
427
|
+
tablename,
|
|
428
|
+
fkList
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const tplFilePath = path.join(__dirname, 'templates', 'sqlAddForeignKey.ejs')
|
|
432
|
+
const template = await fs.readFile(tplFilePath, 'utf-8');
|
|
433
|
+
const sqlAddForeignKey = ejs.render(template, variables)
|
|
434
|
+
|
|
435
|
+
await db.none(sqlAddForeignKey)
|
|
436
|
+
script.push(sqlAddForeignKey)
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
return script.join("\n")
|
|
440
|
+
} catch (err) {
|
|
441
|
+
throw err
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
/*
|
|
448
|
+
|
|
449
|
+
2509010000000000001
|
|
450
|
+
9223372036854775807
|
|
451
|
+
|
|
452
|
+
company code: 01: TFI, 02: Metro
|
|
453
|
+
--
|
|
454
|
+
JV01.2501.000000
|
|
455
|
+
JV02.2501.000000
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
header sequencer
|
|
459
|
+
2501 00 000 00 00000000
|
|
460
|
+
---- -- --- -- --------
|
|
461
|
+
monthly
|
|
462
|
+
doc
|
|
463
|
+
block
|
|
464
|
+
cluster
|
|
465
|
+
runnning number
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
detil sequencer
|
|
469
|
+
2501 000,000,000,000,000
|
|
470
|
+
montyly
|
|
471
|
+
running number
|
|
472
|
+
|
|
473
|
+
*/
|
|
474
|
+
|
|
475
|
+
|