@gzl10/osx-cli 4.0.5 → 4.0.7
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/README.md +22 -1
- package/dist/{chunk-R65IT4N7.js → chunk-Q7WNFJU6.js} +47 -15
- package/dist/cli.js +36 -7
- package/dist/index.d.ts +8 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -51,7 +51,11 @@ osx extract TABLA --tns PROD_DB
|
|
|
51
51
|
# Multiples tablas
|
|
52
52
|
osx extract TABLA1,TABLA2,TABLA3 --tns PROD_DB
|
|
53
53
|
|
|
54
|
-
#
|
|
54
|
+
# Wildcards: * (multiples caracteres), ? (un caracter)
|
|
55
|
+
osx extract "D21*" --tns PROD_DB -o --pretty
|
|
56
|
+
osx extract "A200?100" --tns PROD_DB -o
|
|
57
|
+
|
|
58
|
+
# Guardar en archivo (nombre auto: TABLA.json o extractYYYYMMDD.json)
|
|
55
59
|
osx extract TABLA --tns PROD_DB -o --pretty
|
|
56
60
|
|
|
57
61
|
# Guardar con nombre especifico
|
|
@@ -67,6 +71,23 @@ osx extract TABLA --tns "servidor:1521/servicio" -u USER -p PASS
|
|
|
67
71
|
osx extract TABLA --tns PROD_DB --schema OWNER_SCHEMA
|
|
68
72
|
```
|
|
69
73
|
|
|
74
|
+
### Wildcards
|
|
75
|
+
|
|
76
|
+
Los wildcards permiten extraer multiples tablas con un patron:
|
|
77
|
+
|
|
78
|
+
- `*` - coincide con cualquier cantidad de caracteres
|
|
79
|
+
- `?` - coincide con un solo caracter
|
|
80
|
+
|
|
81
|
+
Cuando se usan wildcards, se aplica automaticamente un delay de 100ms entre tablas para no saturar la base de datos. Puedes ajustarlo con `-d`.
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# Todas las tablas que empiezan por D21
|
|
85
|
+
osx extract "D21*" --tns PROD_DB -o --pretty
|
|
86
|
+
|
|
87
|
+
# Con delay personalizado (500ms)
|
|
88
|
+
osx extract "D21*" --tns PROD_DB -o --pretty -d 500
|
|
89
|
+
```
|
|
90
|
+
|
|
70
91
|
## Opciones
|
|
71
92
|
|
|
72
93
|
| Opcion | Descripcion |
|
|
@@ -49,6 +49,9 @@ var OracleService = class {
|
|
|
49
49
|
* Conecta a Oracle usando TNS
|
|
50
50
|
*/
|
|
51
51
|
async connect(config) {
|
|
52
|
+
if (!process.env.NLS_LANG) {
|
|
53
|
+
process.env.NLS_LANG = "SPANISH_SPAIN.AL32UTF8";
|
|
54
|
+
}
|
|
52
55
|
initThickMode();
|
|
53
56
|
this.connection = await oracledb.getConnection({
|
|
54
57
|
user: config.user,
|
|
@@ -88,6 +91,16 @@ var TABLE_COMMENT = `
|
|
|
88
91
|
WHERE owner = :schema AND table_name = :tableName
|
|
89
92
|
`;
|
|
90
93
|
var TABLE_COLUMNS = `
|
|
94
|
+
WITH PK_COLUMNS AS (
|
|
95
|
+
SELECT acc.COLUMN_NAME
|
|
96
|
+
FROM ALL_CONSTRAINTS ac
|
|
97
|
+
JOIN ALL_CONS_COLUMNS acc
|
|
98
|
+
ON ac.CONSTRAINT_NAME = acc.CONSTRAINT_NAME
|
|
99
|
+
AND ac.OWNER = acc.OWNER
|
|
100
|
+
WHERE ac.CONSTRAINT_TYPE = 'P'
|
|
101
|
+
AND ac.OWNER = :schema
|
|
102
|
+
AND ac.TABLE_NAME = :tableName
|
|
103
|
+
)
|
|
91
104
|
SELECT
|
|
92
105
|
COLS.COLUMN_NAME as "column_name",
|
|
93
106
|
DESCRIP.COMMENTS as "comment",
|
|
@@ -96,28 +109,19 @@ var TABLE_COLUMNS = `
|
|
|
96
109
|
COLS.DATA_PRECISION as "data_precision",
|
|
97
110
|
COLS.NULLABLE as "nullable",
|
|
98
111
|
CASE WHEN PK.COLUMN_NAME IS NOT NULL THEN 'Y' ELSE 'N' END AS "is_pk"
|
|
99
|
-
FROM
|
|
100
|
-
JOIN
|
|
112
|
+
FROM ALL_TAB_COLUMNS COLS
|
|
113
|
+
JOIN ALL_COL_COMMENTS DESCRIP
|
|
101
114
|
ON DESCRIP.OWNER = COLS.OWNER
|
|
102
115
|
AND DESCRIP.TABLE_NAME = COLS.TABLE_NAME
|
|
103
116
|
AND DESCRIP.COLUMN_NAME = COLS.COLUMN_NAME
|
|
104
|
-
LEFT JOIN
|
|
105
|
-
SELECT acc.COLUMN_NAME
|
|
106
|
-
FROM ALL_CONSTRAINTS ac
|
|
107
|
-
JOIN ALL_CONS_COLUMNS acc
|
|
108
|
-
ON ac.OWNER = acc.OWNER
|
|
109
|
-
AND ac.CONSTRAINT_NAME = acc.CONSTRAINT_NAME
|
|
110
|
-
WHERE ac.CONSTRAINT_TYPE = 'P'
|
|
111
|
-
AND ac.OWNER = :schema
|
|
112
|
-
AND acc.TABLE_NAME = :tableName
|
|
113
|
-
) PK ON PK.COLUMN_NAME = COLS.COLUMN_NAME
|
|
117
|
+
LEFT JOIN PK_COLUMNS PK ON PK.COLUMN_NAME = COLS.COLUMN_NAME
|
|
114
118
|
WHERE COLS.OWNER = :schema AND COLS.TABLE_NAME = :tableName
|
|
115
119
|
ORDER BY COLS.COLUMN_ID
|
|
116
120
|
`;
|
|
117
121
|
var TABLE_CHILDREN = `
|
|
118
122
|
SELECT DISTINCT ac_child.table_name AS "child_table"
|
|
119
|
-
FROM
|
|
120
|
-
JOIN
|
|
123
|
+
FROM ALL_CONSTRAINTS ac_parent
|
|
124
|
+
JOIN ALL_CONSTRAINTS ac_child
|
|
121
125
|
ON ac_parent.constraint_name = ac_child.r_constraint_name
|
|
122
126
|
AND ac_parent.owner = ac_child.r_owner
|
|
123
127
|
WHERE ac_parent.owner = :schema
|
|
@@ -131,15 +135,43 @@ var TABLE_STATS = `
|
|
|
131
135
|
FROM ALL_TABLES
|
|
132
136
|
WHERE OWNER = :schema AND TABLE_NAME = :tableName
|
|
133
137
|
`;
|
|
138
|
+
var ORACLE_IDENTIFIER_REGEX = /^[A-Z][A-Z0-9_#$]{0,127}$/i;
|
|
139
|
+
function validateOracleIdentifier(name, type) {
|
|
140
|
+
if (!ORACLE_IDENTIFIER_REGEX.test(name)) {
|
|
141
|
+
throw new Error(`Nombre de ${type} inv\xE1lido: ${name}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
134
144
|
function buildExamplesQuery(schema, tableName, limit = 10) {
|
|
135
|
-
|
|
145
|
+
validateOracleIdentifier(schema, "schema");
|
|
146
|
+
validateOracleIdentifier(tableName, "tabla");
|
|
147
|
+
const safeLimit = Math.min(Math.max(1, limit), 100);
|
|
148
|
+
return `SELECT * FROM ${schema}.${tableName} FETCH FIRST ${safeLimit} ROWS ONLY`;
|
|
136
149
|
}
|
|
150
|
+
var LIST_TABLES = `
|
|
151
|
+
SELECT TABLE_NAME as "table_name"
|
|
152
|
+
FROM ALL_TABLES
|
|
153
|
+
WHERE OWNER = :schema
|
|
154
|
+
AND TABLE_NAME LIKE :pattern
|
|
155
|
+
ORDER BY TABLE_NAME
|
|
156
|
+
`;
|
|
137
157
|
|
|
138
158
|
// src/services/SchemaExtractor.ts
|
|
139
159
|
var SchemaExtractor = class {
|
|
140
160
|
constructor(oracle) {
|
|
141
161
|
this.oracle = oracle;
|
|
142
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* Lista tablas que coinciden con un patrón
|
|
165
|
+
* Convierte wildcards: * → %, ? → _
|
|
166
|
+
*/
|
|
167
|
+
async listTables(schema, pattern) {
|
|
168
|
+
const sqlPattern = pattern.replace(/\*/g, "%").replace(/\?/g, "_");
|
|
169
|
+
const rows = await this.oracle.query(LIST_TABLES, {
|
|
170
|
+
schema,
|
|
171
|
+
pattern: sqlPattern
|
|
172
|
+
});
|
|
173
|
+
return rows.map((r) => r.table_name);
|
|
174
|
+
}
|
|
143
175
|
/**
|
|
144
176
|
* Extrae el esquema completo de una tabla
|
|
145
177
|
*/
|
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
OracleService,
|
|
4
4
|
SchemaExtractor
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-Q7WNFJU6.js";
|
|
6
6
|
|
|
7
7
|
// src/cli.ts
|
|
8
8
|
import { readFileSync as readFileSync2 } from "fs";
|
|
@@ -120,7 +120,6 @@ async function extractCommand(tables, options) {
|
|
|
120
120
|
const homeEnv = loadHomeEnv();
|
|
121
121
|
const user = options.user || process.env.OSX_USER || homeEnv.user;
|
|
122
122
|
const password = options.password || process.env.OSX_PASSWORD || homeEnv.password;
|
|
123
|
-
const schema = options.schema || user?.toUpperCase();
|
|
124
123
|
if (!options.tns) {
|
|
125
124
|
console.error(
|
|
126
125
|
'\n\u274C Error: Debes especificar el TNS o conexi\xF3n\n\nUso:\n osx extract <TABLA> --tns <ALIAS> # Usa tnsnames.ora\n osx extract <TABLA> --tns host:port/sid # Easy Connect\n\nEjemplos:\n osx extract D0001 --tns MDI1\n osx extract D0001 --tns "BDMDI1:1523/MDI1"\n'
|
|
@@ -133,21 +132,51 @@ async function extractCommand(tables, options) {
|
|
|
133
132
|
);
|
|
134
133
|
process.exit(1);
|
|
135
134
|
}
|
|
135
|
+
const schema = options.schema || user.toUpperCase();
|
|
136
136
|
setupTnsAdmin();
|
|
137
137
|
const oracle = new OracleService();
|
|
138
138
|
try {
|
|
139
139
|
console.error(`Conectando a ${options.tns}...`);
|
|
140
140
|
await oracle.connect({ tns: options.tns, user, password });
|
|
141
|
-
const
|
|
142
|
-
if (
|
|
141
|
+
const tablePatterns = tables.split(",").map((t) => t.trim().toUpperCase()).filter(Boolean);
|
|
142
|
+
if (tablePatterns.length === 0) {
|
|
143
143
|
console.error(
|
|
144
|
-
|
|
144
|
+
'\n\u274C Error: No se especificaron tablas a extraer\n\nUso: osx extract <TABLA> [--tns ALIAS]\n\nEjemplos:\n osx extract D0001 --tns TRON_LD\n osx extract D0001,D0002,D0003 --tns TRON_LD\n osx extract "D21*" --tns TRON_LD # Wildcards\n'
|
|
145
145
|
);
|
|
146
146
|
process.exit(1);
|
|
147
147
|
}
|
|
148
|
-
console.error(`Extrayendo ${tableNames.length} tabla(s) de ${schema}...`);
|
|
149
148
|
const extractor = new SchemaExtractor(oracle);
|
|
150
|
-
const
|
|
149
|
+
const hasWildcards = tablePatterns.some((p) => p.includes("*") || p.includes("?"));
|
|
150
|
+
let tableNames = [];
|
|
151
|
+
if (hasWildcards) {
|
|
152
|
+
console.error(`Buscando tablas en ${schema}...`);
|
|
153
|
+
for (const pattern of tablePatterns) {
|
|
154
|
+
if (pattern.includes("*") || pattern.includes("?")) {
|
|
155
|
+
const matched = await extractor.listTables(schema, pattern);
|
|
156
|
+
if (matched.length === 0) {
|
|
157
|
+
console.error(` \u26A0\uFE0F No se encontraron tablas para: ${pattern}`);
|
|
158
|
+
} else {
|
|
159
|
+
console.error(` \u2713 ${pattern} \u2192 ${matched.length} tabla(s)`);
|
|
160
|
+
tableNames.push(...matched);
|
|
161
|
+
}
|
|
162
|
+
} else {
|
|
163
|
+
tableNames.push(pattern);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
tableNames = [...new Set(tableNames)].sort();
|
|
167
|
+
if (tableNames.length === 0) {
|
|
168
|
+
console.error("\n\u274C Error: No se encontraron tablas que coincidan con los patrones\n");
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|
|
171
|
+
console.error(`
|
|
172
|
+
Tablas a extraer (${tableNames.length}):`);
|
|
173
|
+
tableNames.forEach((t) => console.error(` - ${t}`));
|
|
174
|
+
console.error("");
|
|
175
|
+
} else {
|
|
176
|
+
tableNames = tablePatterns;
|
|
177
|
+
}
|
|
178
|
+
console.error(`Extrayendo ${tableNames.length} tabla(s) de ${schema}...`);
|
|
179
|
+
const delayMs = options.delay ? parseInt(options.delay, 10) : hasWildcards ? 100 : 0;
|
|
151
180
|
const results = await extractor.extractTables(options.tns, schema, tableNames, delayMs);
|
|
152
181
|
const output = results.length === 1 ? results[0] : results;
|
|
153
182
|
const json = options.pretty ? JSON.stringify(output, null, 2) : JSON.stringify(output);
|
package/dist/index.d.ts
CHANGED
|
@@ -70,6 +70,11 @@ declare class OracleService {
|
|
|
70
70
|
declare class SchemaExtractor {
|
|
71
71
|
private oracle;
|
|
72
72
|
constructor(oracle: OracleService);
|
|
73
|
+
/**
|
|
74
|
+
* Lista tablas que coinciden con un patrón
|
|
75
|
+
* Convierte wildcards: * → %, ? → _
|
|
76
|
+
*/
|
|
77
|
+
listTables(schema: string, pattern: string): Promise<string[]>;
|
|
73
78
|
/**
|
|
74
79
|
* Extrae el esquema completo de una tabla
|
|
75
80
|
*/
|
|
@@ -87,11 +92,12 @@ declare const TABLE_COMMENT = "\n SELECT comments\n FROM ALL_TAB_COMMENTS\n W
|
|
|
87
92
|
/**
|
|
88
93
|
* Query para obtener las columnas de una tabla con sus metadatos
|
|
89
94
|
* Incluye: nombre, comentario, tipo de dato, nullable, si es PK
|
|
95
|
+
* Usa CTE para evaluar la subquery de PK una sola vez
|
|
90
96
|
*/
|
|
91
|
-
declare const TABLE_COLUMNS = "\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
|
|
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";
|
|
92
98
|
/**
|
|
93
99
|
* Query para obtener las tablas hijas (que tienen FK hacia esta tabla)
|
|
94
100
|
*/
|
|
95
|
-
declare const TABLE_CHILDREN = "\n SELECT DISTINCT ac_child.table_name AS \"child_table\"\n FROM
|
|
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";
|
|
96
102
|
|
|
97
103
|
export { type ExtractOptions, type OracleColumn, type OracleConfig, OracleService, SchemaExtractor, TABLE_CHILDREN, TABLE_COLUMNS, TABLE_COMMENT, type TableSchema };
|
package/dist/index.js
CHANGED