@cosider.construction/eapp 1.0.4 → 1.0.5
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/package.json +1 -1
- package/src/generators/entity.js +81 -68
- package/src/generators/menu.js +2 -2
- package/src/utils/naming.js +56 -62
package/package.json
CHANGED
package/src/generators/entity.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { parseEntityPath, ipcRoute, toUpper, toLower, toPascal } from '../utils/naming.js';
|
|
4
|
-
import { writeFile, writeJson, exists, assertProjectRoot
|
|
4
|
+
import { writeFile, writeJson, exists, assertProjectRoot } from '../utils/fs.js';
|
|
5
5
|
import { log } from '../utils/log.js';
|
|
6
|
-
import { textInput, optionsLine, fieldsTable
|
|
6
|
+
import { textInput, optionsLine, fieldsTable } from '../tui/engine.js';
|
|
7
7
|
|
|
8
8
|
// ─── Default fields ───────────────────────────────────────────────────────────
|
|
9
9
|
|
|
10
10
|
function defaultFillableRows(entityName) {
|
|
11
11
|
return [
|
|
12
|
-
{ field: `${entityName}_id`,
|
|
13
|
-
{ field: `${entityName}_lib`, type: 'varchar',
|
|
12
|
+
{ field: `${entityName}_id`, type: 'int', values: '', pk: true, fk: false, group: '' },
|
|
13
|
+
{ field: `${entityName}_lib`, type: 'varchar', values: '', pk: false, fk: false, group: '' },
|
|
14
14
|
];
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -29,11 +29,14 @@ const AUDIT_WIDTHS = { field: 20, type: 10 };
|
|
|
29
29
|
// ─── Code generators ──────────────────────────────────────────────────────────
|
|
30
30
|
|
|
31
31
|
function buildModelJs({ module, entity, table, schema, fields, auditFields, pkField }) {
|
|
32
|
-
const TABLE
|
|
33
|
-
const dbAlias
|
|
34
|
-
|
|
32
|
+
const TABLE = toUpper(table || entity);
|
|
33
|
+
const dbAlias = schema === 'dbo' ? 'dbo' : schema;
|
|
34
|
+
// import path: shared entities are 3 levels deep (shared/ENTITY/model.js → engine/db.js)
|
|
35
|
+
// module entities are also 3 levels deep (modules/MOD/ENTITY/model.js → engine/db.js)
|
|
36
|
+
const importPath = module === 'shared'
|
|
37
|
+
? '../../../engine/db.js'
|
|
38
|
+
: '../../../engine/db.js';
|
|
35
39
|
|
|
36
|
-
const allFields = [...fields, ...auditFields];
|
|
37
40
|
const fillable = fields.filter(f => !f.pk);
|
|
38
41
|
const insertCols = fillable.map(f => f.field).join(', ');
|
|
39
42
|
const insertVals = fillable.map(f => `@${f.field}`).join(', ');
|
|
@@ -44,6 +47,7 @@ function buildModelJs({ module, entity, table, schema, fields, auditFields, pkFi
|
|
|
44
47
|
// Table : ${TABLE}
|
|
45
48
|
// Schema : ${schema}
|
|
46
49
|
// PK : ${pkField}
|
|
50
|
+
// The scoped DB instance automatically prepends [database].[${schema}] to table names.
|
|
47
51
|
|
|
48
52
|
export async function getAll() {
|
|
49
53
|
return db.query('SELECT * FROM ${TABLE}');
|
|
@@ -56,20 +60,20 @@ export async function getById(${pkField}) {
|
|
|
56
60
|
export async function add(data) {
|
|
57
61
|
const { ${fillable.map(f => f.field).join(', ') || '/* fields */'} } = data;
|
|
58
62
|
return db.execute(
|
|
59
|
-
|
|
63
|
+
\`INSERT INTO ${TABLE} (${insertCols || '/* cols */'}) VALUES (${insertVals || '/* vals */'})\`,
|
|
60
64
|
data
|
|
61
65
|
);
|
|
62
66
|
}
|
|
63
67
|
|
|
64
68
|
export async function update(${pkField}, data) {
|
|
65
69
|
return db.execute(
|
|
66
|
-
|
|
70
|
+
\`UPDATE ${TABLE} SET ${updateSet || '/* set clause */'} WHERE ${pkField} = @${pkField}\`,
|
|
67
71
|
{ ...data, ${pkField} }
|
|
68
72
|
);
|
|
69
73
|
}
|
|
70
74
|
|
|
71
75
|
export async function remove(${pkField}) {
|
|
72
|
-
return db.execute(
|
|
76
|
+
return db.execute(\`DELETE FROM ${TABLE} WHERE ${pkField} = @${pkField}\`, { ${pkField} });
|
|
73
77
|
}
|
|
74
78
|
`;
|
|
75
79
|
}
|
|
@@ -77,15 +81,15 @@ export async function remove(${pkField}) {
|
|
|
77
81
|
function buildControllerJs({ pkField }) {
|
|
78
82
|
return `import * as model from './model.js';
|
|
79
83
|
|
|
80
|
-
export async function getAll()
|
|
81
|
-
export async function getById(${pkField})
|
|
82
|
-
export async function add(data)
|
|
83
|
-
export async function update(${pkField}, data)
|
|
84
|
-
export async function remove(${pkField})
|
|
84
|
+
export async function getAll() { return model.getAll(); }
|
|
85
|
+
export async function getById(${pkField}) { return model.getById(${pkField}); }
|
|
86
|
+
export async function add(data) { return model.add(data); }
|
|
87
|
+
export async function update(${pkField}, data) { return model.update(${pkField}, data); }
|
|
88
|
+
export async function remove(${pkField}) { return model.remove(${pkField}); }
|
|
85
89
|
`;
|
|
86
90
|
}
|
|
87
91
|
|
|
88
|
-
function buildIpcJson({ module, entity,
|
|
92
|
+
function buildIpcJson({ module, entity, schema }) {
|
|
89
93
|
const route = ipcRoute(module, entity);
|
|
90
94
|
const mod = module === 'shared' ? 'shared' : module;
|
|
91
95
|
const ent = toLower(entity);
|
|
@@ -115,51 +119,69 @@ export default new ${ClassName}();
|
|
|
115
119
|
`;
|
|
116
120
|
}
|
|
117
121
|
|
|
118
|
-
function buildMetaJson({ module, entity, schema, fields, auditFields, pkField }) {
|
|
119
|
-
return JSON.stringify({ module, entity, schema, fields, auditFields, pkField }, null, 2);
|
|
122
|
+
function buildMetaJson({ module, entity, table, schema, fields, auditFields, pkField }) {
|
|
123
|
+
return JSON.stringify({ module, entity, table, schema, fields, auditFields, pkField }, null, 2);
|
|
120
124
|
}
|
|
121
125
|
|
|
122
126
|
// ─── Write entity files ───────────────────────────────────────────────────────
|
|
123
127
|
|
|
124
128
|
async function writeEntity({ module, entity, table, schema, fields, auditFields, pkField, opts, dryRun }) {
|
|
125
129
|
const cwd = process.cwd();
|
|
126
|
-
|
|
127
|
-
|
|
130
|
+
|
|
131
|
+
// Display path
|
|
132
|
+
const displayPath = `${module}/${entity}` +
|
|
133
|
+
(table !== entity ? `:${table}` : '') +
|
|
134
|
+
`.${schema}`;
|
|
128
135
|
console.log('');
|
|
129
136
|
console.log(chalk.bold.white(' Entity ') + chalk.cyan(displayPath));
|
|
130
|
-
if (
|
|
131
|
-
console.log(chalk.dim(` table name
|
|
137
|
+
if (table !== entity) {
|
|
138
|
+
console.log(chalk.dim(` DB table name: ${toUpper(table)}`));
|
|
132
139
|
}
|
|
133
140
|
|
|
134
|
-
const backendBase = module === 'shared'
|
|
141
|
+
const backendBase = module === 'shared'
|
|
135
142
|
? path.join(cwd, 'src', 'backend', 'shared', toUpper(entity))
|
|
136
143
|
: path.join(cwd, 'src', 'backend', 'modules', toUpper(module), toUpper(entity));
|
|
137
144
|
|
|
138
145
|
const o = opts || { model: true, controller: true, crud: true, api: true, ipc: true };
|
|
139
146
|
|
|
140
147
|
if (o.model) {
|
|
141
|
-
await writeFile(
|
|
142
|
-
|
|
148
|
+
await writeFile(
|
|
149
|
+
path.join(backendBase, 'model.js'),
|
|
150
|
+
buildModelJs({ module, entity, table, schema, fields, auditFields, pkField }),
|
|
151
|
+
{ dryRun }
|
|
152
|
+
);
|
|
143
153
|
}
|
|
144
154
|
if (o.controller) {
|
|
145
|
-
await writeFile(
|
|
146
|
-
|
|
155
|
+
await writeFile(
|
|
156
|
+
path.join(backendBase, 'controller.js'),
|
|
157
|
+
buildControllerJs({ pkField }),
|
|
158
|
+
{ dryRun }
|
|
159
|
+
);
|
|
147
160
|
}
|
|
148
161
|
if (o.ipc) {
|
|
149
|
-
await writeFile(
|
|
150
|
-
|
|
162
|
+
await writeFile(
|
|
163
|
+
path.join(backendBase, 'ipc.json'),
|
|
164
|
+
buildIpcJson({ module, entity, schema }),
|
|
165
|
+
{ dryRun }
|
|
166
|
+
);
|
|
151
167
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
168
|
+
|
|
169
|
+
// Always write meta — entity registry reads this
|
|
170
|
+
await writeJson(
|
|
171
|
+
path.join(backendBase, 'entity.meta.json'),
|
|
172
|
+
{ module, entity, table, schema, fields, auditFields, pkField },
|
|
173
|
+
{ dryRun }
|
|
174
|
+
);
|
|
155
175
|
|
|
156
176
|
if (o.api && o.ipc) {
|
|
157
|
-
const apiPath = path.join(
|
|
158
|
-
|
|
177
|
+
const apiPath = path.join(
|
|
178
|
+
cwd, 'src', 'frontend', 'api', 'modules',
|
|
179
|
+
`${toLower(module)}.${toLower(entity)}.api.js`
|
|
180
|
+
);
|
|
159
181
|
await writeFile(apiPath, buildApiJs({ module, entity }), { dryRun });
|
|
160
182
|
}
|
|
161
183
|
|
|
162
|
-
log.success(`Entity ${chalk.cyan(
|
|
184
|
+
log.success(`Entity ${chalk.cyan(displayPath)} generated.`);
|
|
163
185
|
}
|
|
164
186
|
|
|
165
187
|
// ─── Main generator ───────────────────────────────────────────────────────────
|
|
@@ -175,10 +197,12 @@ export async function generateEntity(args, rawArgs) {
|
|
|
175
197
|
console.log('');
|
|
176
198
|
console.log(chalk.bold.cyan(' eapp entity') + chalk.dim(' <module/entity.schema>'));
|
|
177
199
|
console.log('');
|
|
178
|
-
console.log(chalk.dim(' /employee → shared
|
|
200
|
+
console.log(chalk.dim(' /employee → shared, employee, dbo'));
|
|
179
201
|
console.log(chalk.dim(' rh/employee → rh module, rh schema'));
|
|
180
202
|
console.log(chalk.dim(' rh/employee.dbo → rh module, dbo schema'));
|
|
181
|
-
console.log(chalk.dim(' rh/employee.hr → rh module, custom schema
|
|
203
|
+
console.log(chalk.dim(' rh/employee.hr → rh module, custom schema'));
|
|
204
|
+
console.log(chalk.dim(' POLE.dbo → shared, pole entity, dbo schema'));
|
|
205
|
+
console.log(chalk.dim(' rh/agent:AGENTX → rh module, entity=agent, table=AGENTX'));
|
|
182
206
|
console.log('');
|
|
183
207
|
}
|
|
184
208
|
|
|
@@ -194,38 +218,27 @@ export async function generateEntity(args, rawArgs) {
|
|
|
194
218
|
catch (e) { log.error(e.message); process.exit(1); }
|
|
195
219
|
}
|
|
196
220
|
|
|
197
|
-
const { module, entity, table
|
|
198
|
-
const
|
|
199
|
-
let tableOverride = parsedTable !== entity ? parsedTable : null;
|
|
221
|
+
const { module, entity, table, schema } = parsed;
|
|
222
|
+
const defaultPk = `${entity}_id`;
|
|
200
223
|
|
|
201
224
|
// ── Check if exists ───────────────────────────────────────────────────────
|
|
202
225
|
const cwd = process.cwd();
|
|
203
|
-
|
|
204
|
-
const displayPath = `${module}/${entity}` + (parsedTable !== entity ? `:${parsedTable}` : '') + `.${schema}`;
|
|
205
|
-
console.log('');
|
|
206
|
-
console.log(chalk.bold.white(' Entity ') + chalk.cyan(displayPath));
|
|
207
|
-
if (parsedTable !== entity) {
|
|
208
|
-
console.log(chalk.dim(` table name in DB will be: ${toUpper(parsedTable)}`));
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
const backendBase = module === 'shared'
|
|
226
|
+
const backendBase = module === 'shared'
|
|
212
227
|
? path.join(cwd, 'src', 'backend', 'shared', toUpper(entity))
|
|
213
228
|
: path.join(cwd, 'src', 'backend', 'modules', toUpper(module), toUpper(entity));
|
|
214
229
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
log.info(`Entity ${chalk.cyan(module + '/' + entity)} already exists.`);
|
|
218
|
-
log.dim(' Regenerating files — existing logic will be preserved in model/controller.');
|
|
230
|
+
if (await exists(backendBase)) {
|
|
231
|
+
log.info(`Entity ${chalk.cyan(module + '/' + entity)} already exists — regenerating.`);
|
|
219
232
|
}
|
|
220
233
|
|
|
221
|
-
// ── --default:
|
|
234
|
+
// ── --default: instant generation ────────────────────────────────────────
|
|
222
235
|
if (useDefault) {
|
|
223
236
|
await writeEntity({
|
|
224
|
-
module, entity, table
|
|
225
|
-
fields:
|
|
237
|
+
module, entity, table, schema,
|
|
238
|
+
fields: defaultFillableRows(entity),
|
|
226
239
|
auditFields: DEFAULT_AUDIT_ROWS,
|
|
227
|
-
pkField,
|
|
228
|
-
opts:
|
|
240
|
+
pkField: defaultPk,
|
|
241
|
+
opts: { model: true, controller: true, crud: true, api: true, ipc: true },
|
|
229
242
|
dryRun,
|
|
230
243
|
});
|
|
231
244
|
return;
|
|
@@ -242,7 +255,7 @@ export async function generateEntity(args, rawArgs) {
|
|
|
242
255
|
{ key: 'ipc', label: 'IPC', default: true },
|
|
243
256
|
]);
|
|
244
257
|
|
|
245
|
-
// ── Fillable fields
|
|
258
|
+
// ── Fillable fields table ─────────────────────────────────────────────────
|
|
246
259
|
const fillableRows = await fieldsTable(
|
|
247
260
|
defaultFillableRows(entity),
|
|
248
261
|
FILLABLE_COLS,
|
|
@@ -250,23 +263,23 @@ export async function generateEntity(args, rawArgs) {
|
|
|
250
263
|
'Fillable Fields (+ add - remove ← → cols ↑ ↓ rows space pk/fk enter done)'
|
|
251
264
|
);
|
|
252
265
|
|
|
253
|
-
// ── Audit fields
|
|
266
|
+
// ── Audit fields table ────────────────────────────────────────────────────
|
|
254
267
|
const auditRows = await fieldsTable(
|
|
255
268
|
[...DEFAULT_AUDIT_ROWS],
|
|
256
269
|
AUDIT_COLS,
|
|
257
270
|
AUDIT_WIDTHS,
|
|
258
|
-
'Audit Fields (non-fillable) (- to remove unwanted)'
|
|
271
|
+
'Audit Fields (non-fillable) (- to remove unwanted enter done)'
|
|
259
272
|
);
|
|
260
273
|
|
|
261
|
-
//
|
|
262
|
-
const pkRow
|
|
263
|
-
const resolvedPk = pkRow ? pkRow.field :
|
|
274
|
+
// Resolve PK from fields
|
|
275
|
+
const pkRow = fillableRows.find(r => r.pk);
|
|
276
|
+
const resolvedPk = pkRow ? pkRow.field : defaultPk;
|
|
264
277
|
|
|
265
278
|
await writeEntity({
|
|
266
|
-
module, entity, table
|
|
267
|
-
fields:
|
|
279
|
+
module, entity, table, schema,
|
|
280
|
+
fields: fillableRows,
|
|
268
281
|
auditFields: auditRows,
|
|
269
|
-
pkField:
|
|
282
|
+
pkField: resolvedPk,
|
|
270
283
|
opts,
|
|
271
284
|
dryRun,
|
|
272
285
|
});
|
package/src/generators/menu.js
CHANGED
|
@@ -67,8 +67,8 @@ async function editViewMenu(menuFile, existing) {
|
|
|
67
67
|
console.log('');
|
|
68
68
|
const rows = await fieldsTable(
|
|
69
69
|
existing_items,
|
|
70
|
-
['label', 'route', 'icon', '
|
|
71
|
-
{ label: 16, route: 20, icon:
|
|
70
|
+
['label', 'route', 'icon', 'path', 'dot', 'nbr'],
|
|
71
|
+
{ label: 16, route: 20, icon: 5, path: 14, dot: 5, nbr: 6 },
|
|
72
72
|
'hMenu items (parent = dropdown group label, empty = top level)'
|
|
73
73
|
);
|
|
74
74
|
const menu = { route: existing?.route || '', hMenu: { style: 'classic', items: nestItems(rows) } };
|
package/src/utils/naming.js
CHANGED
|
@@ -15,93 +15,89 @@ export const isValidName = (s) => /^[a-zA-Z0-9_-]+$/.test(s);
|
|
|
15
15
|
/**
|
|
16
16
|
* Parse "module/entity.schema" format
|
|
17
17
|
*
|
|
18
|
-
* /employee
|
|
19
|
-
* rh/employee
|
|
20
|
-
* rh/employee.dbo
|
|
21
|
-
* rh/employee.hr
|
|
22
|
-
* rh/employee.
|
|
23
|
-
* employee
|
|
18
|
+
* /employee → shared, employee, dbo
|
|
19
|
+
* rh/employee → rh, employee, rh
|
|
20
|
+
* rh/employee.dbo → rh, employee, dbo
|
|
21
|
+
* rh/employee.hr → rh, employee, hr
|
|
22
|
+
* rh/employee. → rh, employee, rh (dot alone = module schema)
|
|
23
|
+
* employee → shared, employee, dbo
|
|
24
|
+
* POLE.dbo → shared, pole, dbo (uppercase entity with schema)
|
|
25
|
+
* rh/agent:AGENTX.dbo → rh, agent, dbo, table=agentx
|
|
26
|
+
*
|
|
27
|
+
* OLD compat dot notation: rh.employee → rh/employee
|
|
28
|
+
* BUT: POLE.dbo must NOT rewrite — left has uppercase so it's not a module name
|
|
24
29
|
*/
|
|
25
30
|
export function parseEntityPath(input) {
|
|
26
31
|
if (!input) throw new Error('No entity path provided.');
|
|
27
32
|
|
|
28
33
|
let raw = input.trim();
|
|
29
34
|
|
|
30
|
-
//
|
|
31
|
-
// and the part after is NOT a schema keyword (dbo, etc.) — i.e. "rh.employee" → "rh/employee"
|
|
32
|
-
// BUT "POLE.dbo" must NOT be rewritten — POLE is the entity, dbo is the schema.
|
|
33
|
-
// Rule: rewrite "x.y" only when x contains no uppercase and y is not a known schema.
|
|
34
|
-
const SCHEMA_NAMES = new Set(['dbo', 'dbo2', 'hr', 'rh', 'stk', 'fin', 'crm', 'adm', 'sec', 'shared']);
|
|
35
|
+
// ── Old "module.entity" compat (only if left is strictly lowercase) ────────
|
|
35
36
|
if (!raw.includes('/') && raw.includes('.') && raw.split('.').length === 2) {
|
|
36
37
|
const [left, right] = raw.split('.');
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
if (looksLikeModule && !looksLikeSchema) {
|
|
38
|
+
const leftIsLowercaseModule = /^[a-z][a-z0-9_-]*$/.test(left);
|
|
39
|
+
const rightIsSchemaKeyword = /^(dbo\d*|[a-z]{1,6})$/.test(right.toLowerCase());
|
|
40
|
+
if (leftIsLowercaseModule && !rightIsSchemaKeyword) {
|
|
41
41
|
raw = `${left}/${right}`;
|
|
42
42
|
}
|
|
43
|
+
// Otherwise treat as entity.schema without module (e.g. POLE.dbo, employee.dbo)
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
// No slash
|
|
46
|
+
// ── No slash → shared module ───────────────────────────────────────────────
|
|
46
47
|
if (!raw.includes('/')) {
|
|
47
|
-
const
|
|
48
|
-
|
|
48
|
+
const dotPos = raw.indexOf('.');
|
|
49
|
+
let ent, sch;
|
|
50
|
+
if (dotPos !== -1) {
|
|
51
|
+
ent = toLower(raw.slice(0, dotPos));
|
|
52
|
+
sch = raw.slice(dotPos + 1).toLowerCase() || 'dbo';
|
|
53
|
+
} else {
|
|
54
|
+
ent = toLower(raw);
|
|
55
|
+
sch = 'dbo';
|
|
56
|
+
}
|
|
57
|
+
if (!isValidName(ent)) throw new Error(`Invalid entity name "${ent}".`);
|
|
58
|
+
return { module: 'shared', entity: ent, table: ent, schema: sch };
|
|
49
59
|
}
|
|
50
60
|
|
|
51
|
-
//
|
|
52
|
-
const slashIdx
|
|
53
|
-
const
|
|
54
|
-
const rest
|
|
55
|
-
|
|
56
|
-
const module = modulePart === '' ? 'shared' : toLower(modulePart);
|
|
57
|
-
|
|
58
|
-
// Split entity and schema on .
|
|
59
|
-
const dotIdx = rest.indexOf('.');
|
|
60
|
-
let entity, schema;
|
|
61
|
+
// ── Has slash ─────────────────────────────────────────────────────────────
|
|
62
|
+
const slashIdx = raw.indexOf('/');
|
|
63
|
+
const modPart = raw.slice(0, slashIdx);
|
|
64
|
+
const rest = raw.slice(slashIdx + 1);
|
|
65
|
+
const module = modPart === '' ? 'shared' : toLower(modPart);
|
|
61
66
|
|
|
62
|
-
//
|
|
63
|
-
// e.g. rh/agent:agentx.dbo → entity=agent, table=agentx, schema=dbo
|
|
67
|
+
// ── Optional table alias: entity:TABLE.schema ──────────────────────────────
|
|
64
68
|
let tableAlias = null;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
69
|
+
let cleanRest = rest;
|
|
70
|
+
const colonPos = rest.indexOf(':');
|
|
71
|
+
if (colonPos !== -1) {
|
|
72
|
+
const beforeColon = rest.slice(0, colonPos);
|
|
73
|
+
const afterColon = rest.slice(colonPos + 1);
|
|
74
|
+
const aliasDot = afterColon.indexOf('.');
|
|
75
|
+
tableAlias = toLower(aliasDot !== -1 ? afterColon.slice(0, aliasDot) : afterColon);
|
|
76
|
+
const schemaRest = aliasDot !== -1 ? afterColon.slice(aliasDot) : '';
|
|
77
|
+
cleanRest = beforeColon + schemaRest;
|
|
74
78
|
}
|
|
75
|
-
const cleanRest = rest.replace(/:([^.]+)/, ''); // strip :alias for entity/schema parsing
|
|
76
79
|
|
|
77
|
-
|
|
80
|
+
// ── Entity and schema ──────────────────────────────────────────────────────
|
|
81
|
+
const dotPos = cleanRest.indexOf('.');
|
|
78
82
|
let entity, schema;
|
|
79
|
-
|
|
83
|
+
|
|
84
|
+
if (dotPos === -1) {
|
|
80
85
|
entity = toLower(cleanRest);
|
|
81
86
|
schema = module === 'shared' ? 'dbo' : module;
|
|
82
87
|
} else {
|
|
83
|
-
entity
|
|
84
|
-
const schemaPart = cleanRest.slice(
|
|
85
|
-
schema
|
|
88
|
+
entity = toLower(cleanRest.slice(0, dotPos));
|
|
89
|
+
const schemaPart = cleanRest.slice(dotPos + 1);
|
|
90
|
+
schema = schemaPart === '' ? (module === 'shared' ? 'dbo' : module) : toLower(schemaPart);
|
|
86
91
|
}
|
|
87
|
-
const table = tableAlias ? toLower(tableAlias) : entity;
|
|
88
|
-
// (keep legacy variable for code below that uses dotIdx)
|
|
89
|
-
const dotIdx = dotIdx2;
|
|
90
92
|
|
|
91
|
-
if (!isValidName(entity)) {
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
if (module !== 'shared' && !isValidName(module)) {
|
|
95
|
-
throw new Error(`Invalid module name "${module}".`);
|
|
96
|
-
}
|
|
93
|
+
if (!isValidName(entity)) throw new Error(`Invalid entity name "${entity}".`);
|
|
94
|
+
if (module !== 'shared' && !isValidName(module)) throw new Error(`Invalid module name "${module}".`);
|
|
97
95
|
|
|
98
|
-
return { module, entity, table:
|
|
96
|
+
return { module, entity, table: tableAlias || entity, schema };
|
|
99
97
|
}
|
|
100
98
|
|
|
101
99
|
/**
|
|
102
|
-
*
|
|
103
|
-
* shared + client → shared.CLIENT
|
|
104
|
-
* rh + employee → modules.RH.EMPLOYEE
|
|
100
|
+
* IPC route: shared.CLIENT or modules.RH.EMPLOYEE
|
|
105
101
|
*/
|
|
106
102
|
export function ipcRoute(module, entity) {
|
|
107
103
|
if (module === 'shared') return `shared.${toUpper(entity)}`;
|
|
@@ -109,11 +105,9 @@ export function ipcRoute(module, entity) {
|
|
|
109
105
|
}
|
|
110
106
|
|
|
111
107
|
/**
|
|
112
|
-
*
|
|
108
|
+
* Backend directory for an entity
|
|
113
109
|
*/
|
|
114
110
|
export function backendEntityDir(cwd, module, entity) {
|
|
115
|
-
if (module === 'shared') {
|
|
116
|
-
return `${cwd}/src/backend/shared/${toUpper(entity)}`;
|
|
117
|
-
}
|
|
111
|
+
if (module === 'shared') return `${cwd}/src/backend/shared/${toUpper(entity)}`;
|
|
118
112
|
return `${cwd}/src/backend/modules/${toUpper(module)}/${toUpper(entity)}`;
|
|
119
113
|
}
|