@gzl10/osx-cli 4.0.7 → 4.0.10

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.
@@ -47,17 +47,47 @@ var OracleService = class {
47
47
  connection = null;
48
48
  /**
49
49
  * Conecta a Oracle usando TNS
50
+ * Maneja errores ORA-XXXXX con mensajes descriptivos
50
51
  */
51
52
  async connect(config) {
52
53
  if (!process.env.NLS_LANG) {
53
54
  process.env.NLS_LANG = "SPANISH_SPAIN.AL32UTF8";
54
55
  }
55
56
  initThickMode();
56
- this.connection = await oracledb.getConnection({
57
- user: config.user,
58
- password: config.password,
59
- connectString: config.tns
60
- });
57
+ try {
58
+ this.connection = await oracledb.getConnection({
59
+ user: config.user,
60
+ password: config.password,
61
+ connectString: config.tns
62
+ });
63
+ } catch (err) {
64
+ const oraError = err;
65
+ const code = oraError.errorNum;
66
+ switch (code) {
67
+ case 12154:
68
+ throw new Error(
69
+ `TNS inv\xE1lido: No se pudo resolver '${config.tns}'. Verifica tnsnames.ora o usa formato host:puerto/servicio`
70
+ );
71
+ case 1017:
72
+ throw new Error(`Credenciales inv\xE1lidas para usuario '${config.user}'`);
73
+ case 12170:
74
+ throw new Error(
75
+ `Timeout de conexi\xF3n a '${config.tns}'. Verifica red/firewall`
76
+ );
77
+ case 28040:
78
+ throw new Error(
79
+ `Protocolo de autenticaci\xF3n incompatible. Verifica versi\xF3n de Oracle Instant Client`
80
+ );
81
+ case 12541:
82
+ throw new Error(
83
+ `No hay listener en '${config.tns}'. Verifica que el servicio Oracle est\xE9 activo`
84
+ );
85
+ default:
86
+ throw new Error(
87
+ `Error de conexi\xF3n Oracle: ${oraError.message || String(err)}`
88
+ );
89
+ }
90
+ }
61
91
  }
62
92
  /**
63
93
  * Ejecuta una query con parámetros nombrados
@@ -107,6 +137,7 @@ var TABLE_COLUMNS = `
107
137
  COLS.DATA_TYPE as "data_type",
108
138
  COLS.DATA_LENGTH as "data_length",
109
139
  COLS.DATA_PRECISION as "data_precision",
140
+ COLS.DATA_SCALE as "data_scale",
110
141
  COLS.NULLABLE as "nullable",
111
142
  CASE WHEN PK.COLUMN_NAME IS NOT NULL THEN 'Y' ELSE 'N' END AS "is_pk"
112
143
  FROM ALL_TAB_COLUMNS COLS
@@ -119,16 +150,56 @@ var TABLE_COLUMNS = `
119
150
  ORDER BY COLS.COLUMN_ID
120
151
  `;
121
152
  var TABLE_CHILDREN = `
122
- SELECT DISTINCT ac_child.table_name AS "child_table"
123
- FROM ALL_CONSTRAINTS ac_parent
124
- JOIN ALL_CONSTRAINTS ac_child
125
- ON ac_parent.constraint_name = ac_child.r_constraint_name
126
- AND ac_parent.owner = ac_child.r_owner
127
- WHERE ac_parent.owner = :schema
128
- AND ac_parent.table_name = :tableName
129
- AND ac_parent.constraint_type = 'P'
130
- AND ac_child.constraint_type = 'R'
131
- AND ac_child.status = 'ENABLED'
153
+ WITH FK_RELATIONS AS (
154
+ SELECT
155
+ ac_child.owner AS child_owner,
156
+ ac_child.table_name AS child_table,
157
+ acc_child.column_name AS child_column,
158
+ acc_parent.column_name AS parent_column,
159
+ acc_child.position
160
+ FROM ALL_CONSTRAINTS ac_parent
161
+ JOIN ALL_CONSTRAINTS ac_child
162
+ ON ac_parent.constraint_name = ac_child.r_constraint_name
163
+ AND ac_parent.owner = ac_child.r_owner
164
+ JOIN ALL_CONS_COLUMNS acc_child
165
+ ON ac_child.constraint_name = acc_child.constraint_name
166
+ AND ac_child.owner = acc_child.owner
167
+ JOIN ALL_CONS_COLUMNS acc_parent
168
+ ON ac_parent.constraint_name = acc_parent.constraint_name
169
+ AND ac_parent.owner = acc_parent.owner
170
+ AND acc_child.position = acc_parent.position
171
+ WHERE ac_parent.owner = :schema
172
+ AND ac_parent.table_name = :tableName
173
+ AND ac_parent.constraint_type = 'P'
174
+ AND ac_child.constraint_type = 'R'
175
+ AND ac_child.status = 'ENABLED'
176
+ ),
177
+ UNIQUE_COLS AS (
178
+ SELECT DISTINCT
179
+ uc.owner,
180
+ uc.table_name,
181
+ ucc.column_name
182
+ FROM ALL_CONSTRAINTS uc
183
+ JOIN ALL_CONS_COLUMNS ucc
184
+ ON uc.constraint_name = ucc.constraint_name
185
+ AND uc.owner = ucc.owner
186
+ WHERE uc.constraint_type IN ('P', 'U')
187
+ AND (uc.owner, uc.table_name) IN (
188
+ SELECT DISTINCT child_owner, child_table FROM FK_RELATIONS
189
+ )
190
+ )
191
+ SELECT
192
+ fk.child_table AS "child_table",
193
+ fk.child_column AS "child_column",
194
+ fk.parent_column AS "parent_column",
195
+ fk.position AS "position",
196
+ CASE WHEN uc.column_name IS NOT NULL THEN '1:1' ELSE '1:N' END AS "cardinality"
197
+ FROM FK_RELATIONS fk
198
+ LEFT JOIN UNIQUE_COLS uc
199
+ ON uc.owner = fk.child_owner
200
+ AND uc.table_name = fk.child_table
201
+ AND uc.column_name = fk.child_column
202
+ ORDER BY fk.child_table, fk.position
132
203
  `;
133
204
  var TABLE_STATS = `
134
205
  SELECT NUM_ROWS as "count", LAST_ANALYZED as "last_update"
@@ -188,6 +259,23 @@ var SchemaExtractor = class {
188
259
  schema,
189
260
  tableName
190
261
  });
262
+ const childrenMap = /* @__PURE__ */ new Map();
263
+ for (const row of childrenRows) {
264
+ let relation = childrenMap.get(row.child_table);
265
+ if (!relation) {
266
+ relation = {
267
+ table: row.child_table,
268
+ cardinality: row.cardinality,
269
+ columns: []
270
+ };
271
+ childrenMap.set(row.child_table, relation);
272
+ }
273
+ relation.columns.push({
274
+ child: row.child_column,
275
+ parent: row.parent_column
276
+ });
277
+ }
278
+ const children = Array.from(childrenMap.values());
191
279
  const [statsRow] = await this.oracle.query(TABLE_STATS, {
192
280
  schema,
193
281
  tableName
@@ -200,7 +288,7 @@ var SchemaExtractor = class {
200
288
  name: tableName,
201
289
  comment: commentRow?.COMMENTS || "",
202
290
  columns,
203
- children: childrenRows.map((r) => r.child_table),
291
+ children,
204
292
  count: statsRow?.count ?? 0,
205
293
  lastUpdate: statsRow?.last_update?.toISOString() ?? null,
206
294
  examples
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  OracleService,
4
4
  SchemaExtractor
5
- } from "./chunk-Q7WNFJU6.js";
5
+ } from "./chunk-BZHKOUH7.js";
6
6
 
7
7
  // src/cli.ts
8
8
  import { readFileSync as readFileSync2 } from "fs";
package/dist/index.d.ts CHANGED
@@ -7,9 +7,21 @@ interface OracleColumn {
7
7
  data_type: string;
8
8
  data_length: number | null;
9
9
  data_precision: number | null;
10
+ data_scale: number | null;
10
11
  nullable: 'Y' | 'N';
11
12
  is_pk: 'Y' | 'N';
12
13
  }
14
+ /**
15
+ * Representa una relación FK con una tabla hija
16
+ */
17
+ interface ChildRelation {
18
+ table: string;
19
+ cardinality: '1:1' | '1:N';
20
+ columns: Array<{
21
+ child: string;
22
+ parent: string;
23
+ }>;
24
+ }
13
25
  /**
14
26
  * Esquema de tabla compatible con Atlas OriginType=BBDD
15
27
  */
@@ -19,7 +31,7 @@ interface TableSchema {
19
31
  name: string;
20
32
  comment: string;
21
33
  columns: OracleColumn[];
22
- children: string[];
34
+ children: ChildRelation[];
23
35
  count: number;
24
36
  lastUpdate: string | null;
25
37
  examples: Record<string, unknown>[];
@@ -52,6 +64,7 @@ declare class OracleService {
52
64
  private connection;
53
65
  /**
54
66
  * Conecta a Oracle usando TNS
67
+ * Maneja errores ORA-XXXXX con mensajes descriptivos
55
68
  */
56
69
  connect(config: OracleConfig): Promise<void>;
57
70
  /**
@@ -94,10 +107,13 @@ declare const TABLE_COMMENT = "\n SELECT comments\n FROM ALL_TAB_COMMENTS\n W
94
107
  * Incluye: nombre, comentario, tipo de dato, nullable, si es PK
95
108
  * Usa CTE para evaluar la subquery de PK una sola vez
96
109
  */
97
- declare const TABLE_COLUMNS = "\n WITH PK_COLUMNS AS (\n SELECT acc.COLUMN_NAME\n FROM ALL_CONSTRAINTS ac\n JOIN ALL_CONS_COLUMNS acc\n ON ac.CONSTRAINT_NAME = acc.CONSTRAINT_NAME\n AND ac.OWNER = acc.OWNER\n WHERE ac.CONSTRAINT_TYPE = 'P'\n AND ac.OWNER = :schema\n AND ac.TABLE_NAME = :tableName\n )\n SELECT\n COLS.COLUMN_NAME as \"column_name\",\n DESCRIP.COMMENTS as \"comment\",\n COLS.DATA_TYPE as \"data_type\",\n COLS.DATA_LENGTH as \"data_length\",\n COLS.DATA_PRECISION as \"data_precision\",\n COLS.NULLABLE as \"nullable\",\n CASE WHEN PK.COLUMN_NAME IS NOT NULL THEN 'Y' ELSE 'N' END AS \"is_pk\"\n FROM ALL_TAB_COLUMNS COLS\n JOIN ALL_COL_COMMENTS DESCRIP\n ON DESCRIP.OWNER = COLS.OWNER\n AND DESCRIP.TABLE_NAME = COLS.TABLE_NAME\n AND DESCRIP.COLUMN_NAME = COLS.COLUMN_NAME\n LEFT JOIN PK_COLUMNS PK ON PK.COLUMN_NAME = COLS.COLUMN_NAME\n WHERE COLS.OWNER = :schema AND COLS.TABLE_NAME = :tableName\n ORDER BY COLS.COLUMN_ID\n";
110
+ declare const TABLE_COLUMNS = "\n WITH PK_COLUMNS AS (\n SELECT acc.COLUMN_NAME\n FROM ALL_CONSTRAINTS ac\n JOIN ALL_CONS_COLUMNS acc\n ON ac.CONSTRAINT_NAME = acc.CONSTRAINT_NAME\n AND ac.OWNER = acc.OWNER\n WHERE ac.CONSTRAINT_TYPE = 'P'\n AND ac.OWNER = :schema\n AND ac.TABLE_NAME = :tableName\n )\n SELECT\n COLS.COLUMN_NAME as \"column_name\",\n DESCRIP.COMMENTS as \"comment\",\n COLS.DATA_TYPE as \"data_type\",\n COLS.DATA_LENGTH as \"data_length\",\n COLS.DATA_PRECISION as \"data_precision\",\n COLS.DATA_SCALE as \"data_scale\",\n COLS.NULLABLE as \"nullable\",\n CASE WHEN PK.COLUMN_NAME IS NOT NULL THEN 'Y' ELSE 'N' END AS \"is_pk\"\n FROM ALL_TAB_COLUMNS COLS\n JOIN ALL_COL_COMMENTS DESCRIP\n ON DESCRIP.OWNER = COLS.OWNER\n AND DESCRIP.TABLE_NAME = COLS.TABLE_NAME\n AND DESCRIP.COLUMN_NAME = COLS.COLUMN_NAME\n LEFT JOIN PK_COLUMNS PK ON PK.COLUMN_NAME = COLS.COLUMN_NAME\n WHERE COLS.OWNER = :schema AND COLS.TABLE_NAME = :tableName\n ORDER BY COLS.COLUMN_ID\n";
98
111
  /**
99
112
  * Query para obtener las tablas hijas (que tienen FK hacia esta tabla)
113
+ * Incluye: columnas de la relación y cardinalidad inferida (1:1 si FK tiene UNIQUE/PK)
114
+ *
115
+ * Usa CTEs para evaluar UNIQUE_COLS una sola vez (evita EXISTS anidado por fila)
100
116
  */
101
- declare const TABLE_CHILDREN = "\n SELECT DISTINCT ac_child.table_name AS \"child_table\"\n FROM ALL_CONSTRAINTS ac_parent\n JOIN ALL_CONSTRAINTS ac_child\n ON ac_parent.constraint_name = ac_child.r_constraint_name\n AND ac_parent.owner = ac_child.r_owner\n WHERE ac_parent.owner = :schema\n AND ac_parent.table_name = :tableName\n AND ac_parent.constraint_type = 'P'\n AND ac_child.constraint_type = 'R'\n AND ac_child.status = 'ENABLED'\n";
117
+ declare const TABLE_CHILDREN = "\n WITH FK_RELATIONS AS (\n SELECT\n ac_child.owner AS child_owner,\n ac_child.table_name AS child_table,\n acc_child.column_name AS child_column,\n acc_parent.column_name AS parent_column,\n acc_child.position\n FROM ALL_CONSTRAINTS ac_parent\n JOIN ALL_CONSTRAINTS ac_child\n ON ac_parent.constraint_name = ac_child.r_constraint_name\n AND ac_parent.owner = ac_child.r_owner\n JOIN ALL_CONS_COLUMNS acc_child\n ON ac_child.constraint_name = acc_child.constraint_name\n AND ac_child.owner = acc_child.owner\n JOIN ALL_CONS_COLUMNS acc_parent\n ON ac_parent.constraint_name = acc_parent.constraint_name\n AND ac_parent.owner = acc_parent.owner\n AND acc_child.position = acc_parent.position\n WHERE ac_parent.owner = :schema\n AND ac_parent.table_name = :tableName\n AND ac_parent.constraint_type = 'P'\n AND ac_child.constraint_type = 'R'\n AND ac_child.status = 'ENABLED'\n ),\n UNIQUE_COLS AS (\n SELECT DISTINCT\n uc.owner,\n uc.table_name,\n ucc.column_name\n FROM ALL_CONSTRAINTS uc\n JOIN ALL_CONS_COLUMNS ucc\n ON uc.constraint_name = ucc.constraint_name\n AND uc.owner = ucc.owner\n WHERE uc.constraint_type IN ('P', 'U')\n AND (uc.owner, uc.table_name) IN (\n SELECT DISTINCT child_owner, child_table FROM FK_RELATIONS\n )\n )\n SELECT\n fk.child_table AS \"child_table\",\n fk.child_column AS \"child_column\",\n fk.parent_column AS \"parent_column\",\n fk.position AS \"position\",\n CASE WHEN uc.column_name IS NOT NULL THEN '1:1' ELSE '1:N' END AS \"cardinality\"\n FROM FK_RELATIONS fk\n LEFT JOIN UNIQUE_COLS uc\n ON uc.owner = fk.child_owner\n AND uc.table_name = fk.child_table\n AND uc.column_name = fk.child_column\n ORDER BY fk.child_table, fk.position\n";
102
118
 
103
119
  export { type ExtractOptions, type OracleColumn, type OracleConfig, OracleService, SchemaExtractor, TABLE_CHILDREN, TABLE_COLUMNS, TABLE_COMMENT, type TableSchema };
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  TABLE_CHILDREN,
5
5
  TABLE_COLUMNS,
6
6
  TABLE_COMMENT
7
- } from "./chunk-Q7WNFJU6.js";
7
+ } from "./chunk-BZHKOUH7.js";
8
8
  export {
9
9
  OracleService,
10
10
  SchemaExtractor,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gzl10/osx-cli",
3
- "version": "4.0.7",
3
+ "version": "4.0.10",
4
4
  "description": "Oracle Schema Extractor CLI - Genera JSON compatible con Atlas OriginType=BBDD",
5
5
  "type": "module",
6
6
  "bin": {
@@ -27,15 +27,12 @@
27
27
  "license": "MIT",
28
28
  "dependencies": {
29
29
  "commander": "^13.1.0",
30
- "oracledb": "^6.7.1",
31
- "zod": "^3.24.1"
30
+ "oracledb": "^6.7.1"
32
31
  },
33
32
  "devDependencies": {
34
33
  "@types/node": "^22.10.5",
35
- "@vitest/coverage-v8": "^2.1.8",
36
34
  "tsup": "^8.3.5",
37
- "typescript": "^5.7.3",
38
- "vitest": "^2.1.8"
35
+ "typescript": "^5.7.3"
39
36
  },
40
37
  "engines": {
41
38
  "node": ">=20"