@lark-apaas/miaoda-cli 0.1.2 → 0.1.3-alpha.09899c4
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 +8 -7
- package/dist/api/app/api.js +25 -0
- package/dist/api/app/index.js +15 -0
- package/dist/api/app/schemas.js +79 -0
- package/dist/api/app/types.js +58 -0
- package/dist/api/db/api.js +390 -55
- package/dist/api/db/client.js +65 -25
- package/dist/api/db/index.js +12 -1
- package/dist/api/db/parsers.js +20 -20
- package/dist/api/db/sql-keywords.js +87 -87
- package/dist/api/deploy/api.js +60 -0
- package/dist/api/deploy/index.js +16 -0
- package/dist/api/deploy/schemas.js +105 -0
- package/dist/api/deploy/types.js +22 -0
- package/dist/api/file/api.js +89 -87
- package/dist/api/file/client.js +62 -22
- package/dist/api/file/detect.js +3 -3
- package/dist/api/file/index.js +2 -1
- package/dist/api/file/parsers.js +18 -7
- package/dist/api/index.js +7 -1
- package/dist/api/observability/api.js +52 -0
- package/dist/api/observability/index.js +16 -0
- package/dist/api/observability/schemas.js +60 -0
- package/dist/api/observability/types.js +27 -0
- package/dist/api/plugin/api.js +31 -31
- package/dist/cli/commands/app/index.js +62 -0
- package/dist/cli/commands/db/index.js +600 -59
- package/dist/cli/commands/deploy/index.js +155 -0
- package/dist/cli/commands/file/index.js +91 -63
- package/dist/cli/commands/index.js +10 -6
- package/dist/cli/commands/observability/index.js +240 -0
- package/dist/cli/commands/plugin/index.js +27 -27
- package/dist/cli/commands/shared.js +86 -10
- package/dist/cli/handlers/app/get.js +47 -0
- package/dist/cli/handlers/app/index.js +7 -0
- package/dist/cli/handlers/app/update.js +59 -0
- package/dist/cli/handlers/db/_operator.js +35 -0
- package/dist/cli/handlers/db/audit.js +383 -0
- package/dist/cli/handlers/db/changelog.js +160 -0
- package/dist/cli/handlers/db/data.js +34 -34
- package/dist/cli/handlers/db/index.js +17 -1
- package/dist/cli/handlers/db/migration.js +245 -0
- package/dist/cli/handlers/db/quota.js +68 -0
- package/dist/cli/handlers/db/recovery.js +387 -0
- package/dist/cli/handlers/db/schema.js +35 -36
- package/dist/cli/handlers/db/sql.js +70 -71
- package/dist/cli/handlers/deploy/deploy.js +84 -0
- package/dist/cli/handlers/deploy/error-log.js +60 -0
- package/dist/cli/handlers/deploy/format.js +39 -0
- package/dist/cli/handlers/deploy/get.js +71 -0
- package/dist/cli/handlers/deploy/helpers.js +41 -0
- package/dist/cli/handlers/deploy/history.js +70 -0
- package/dist/cli/handlers/deploy/index.js +14 -0
- package/dist/cli/handlers/deploy/polling.js +162 -0
- package/dist/cli/handlers/file/cp.js +31 -32
- package/dist/cli/handlers/file/index.js +3 -1
- package/dist/cli/handlers/file/ls.js +6 -7
- package/dist/cli/handlers/file/quota.js +66 -0
- package/dist/cli/handlers/file/rm.js +33 -32
- package/dist/cli/handlers/file/sign.js +4 -5
- package/dist/cli/handlers/file/stat.js +11 -11
- package/dist/cli/handlers/observability/analytics.js +212 -0
- package/dist/cli/handlers/observability/helpers.js +66 -0
- package/dist/cli/handlers/observability/index.js +12 -0
- package/dist/cli/handlers/observability/log.js +94 -0
- package/dist/cli/handlers/observability/metric.js +208 -0
- package/dist/cli/handlers/observability/trace.js +102 -0
- package/dist/cli/handlers/plugin/plugin-local.js +53 -53
- package/dist/cli/handlers/plugin/plugin.js +15 -15
- package/dist/cli/help.js +16 -16
- package/dist/main.js +13 -9
- package/dist/utils/args.js +8 -0
- package/dist/utils/colors.js +2 -2
- package/dist/utils/config.js +2 -2
- package/dist/utils/devops-error.js +28 -0
- package/dist/utils/error.js +2 -2
- package/dist/utils/git.js +29 -0
- package/dist/utils/http.js +119 -1
- package/dist/utils/index.js +15 -1
- package/dist/utils/output.js +373 -20
- package/dist/utils/poll.js +35 -0
- package/dist/utils/render.js +27 -27
- package/dist/utils/spinner.js +46 -0
- package/dist/utils/time.js +208 -0
- package/package.json +7 -5
package/dist/api/db/client.js
CHANGED
|
@@ -25,9 +25,9 @@ function traceHttp(method, url, start, response, err) {
|
|
|
25
25
|
try {
|
|
26
26
|
const cost = Date.now() - start;
|
|
27
27
|
const status = response?.status ?? 0;
|
|
28
|
-
const logid = response?.headers?.get?.(
|
|
28
|
+
const logid = response?.headers?.get?.('x-tt-logid') ?? '-';
|
|
29
29
|
if (err !== undefined) {
|
|
30
|
-
const errMsg = err instanceof Error ? err.message : typeof err ===
|
|
30
|
+
const errMsg = err instanceof Error ? err.message : typeof err === 'string' ? err : JSON.stringify(err);
|
|
31
31
|
(0, logger_1.debug)(`http ${method} ${url} ${String(status)} cost=${String(cost)}ms x-tt-logid=${logid} err=${errMsg}`);
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
@@ -46,16 +46,16 @@ function traceHttp(method, url, start, response, err) {
|
|
|
46
46
|
*/
|
|
47
47
|
function ensureInnerSuccess(body) {
|
|
48
48
|
if (!body) {
|
|
49
|
-
throw new error_1.AppError(
|
|
49
|
+
throw new error_1.AppError('INTERNAL_DB_ERROR', 'empty response body');
|
|
50
50
|
}
|
|
51
|
-
const code = body.status_code ?? body.ErrorCode ??
|
|
52
|
-
if (code ===
|
|
51
|
+
const code = body.status_code ?? body.ErrorCode ?? '0';
|
|
52
|
+
if (code === '0' || code === '')
|
|
53
53
|
return;
|
|
54
54
|
const appErr = mapDataloomBizError(code, body.error_msg ?? body.ErrorMessage ?? `dataloom API error [${code}]`);
|
|
55
55
|
// PRD 多语句失败:后端在 envelope 顶层透出 errorStatementIndex(从 0 起计),
|
|
56
56
|
// 单语句 / 单元执行不会带这个字段。挂到 AppError 上让 emitError 落到错误信封
|
|
57
57
|
// statement_index 字段。
|
|
58
|
-
if (typeof body.errorStatementIndex ===
|
|
58
|
+
if (typeof body.errorStatementIndex === 'number') {
|
|
59
59
|
appErr.statement_index = body.errorStatementIndex;
|
|
60
60
|
}
|
|
61
61
|
throw appErr;
|
|
@@ -77,14 +77,14 @@ function ensureInnerSuccess(body) {
|
|
|
77
77
|
*/
|
|
78
78
|
function mapDataloomBizError(code, rawMessage) {
|
|
79
79
|
const message = stripPgPrefix(rawMessage);
|
|
80
|
-
if (code ===
|
|
80
|
+
if (code === 'k_dl_1300002') {
|
|
81
81
|
const sqlstate = extractSqlstate(message);
|
|
82
82
|
if (sqlstate && exports.SQLSTATE_MAP[sqlstate]) {
|
|
83
83
|
return new error_1.AppError(exports.SQLSTATE_MAP[sqlstate], message);
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
|
-
if (code ===
|
|
87
|
-
return new error_1.AppError(
|
|
86
|
+
if (code === 'k_dl_1600000' && message.startsWith('Invalid DB Branch')) {
|
|
87
|
+
return new error_1.AppError('MULTI_ENV_NOT_INITIALIZED', '--env is not available (multi-env not initialized)', { next_actions: ['Verify the --env value matches an existing dbBranch.'] });
|
|
88
88
|
}
|
|
89
89
|
const mapped = BIZ_ERR_MAP.get(code);
|
|
90
90
|
if (mapped) {
|
|
@@ -100,7 +100,7 @@ function mapDataloomBizError(code, rawMessage) {
|
|
|
100
100
|
* 大小写敏感,只匹配 PG 标准格式。
|
|
101
101
|
*/
|
|
102
102
|
function stripPgPrefix(msg) {
|
|
103
|
-
return msg.replace(/^ERROR:\s*/,
|
|
103
|
+
return msg.replace(/^ERROR:\s*/, '');
|
|
104
104
|
}
|
|
105
105
|
/** 从 PG 执行错误消息里提取 "(SQLSTATE XXXXX)"。 */
|
|
106
106
|
function extractSqlstate(msg) {
|
|
@@ -117,27 +117,63 @@ const BIZ_ERR_MAP = new Map(Object.entries({
|
|
|
117
117
|
// 来源:真实环境探测(dataloom InnerExecuteSQL / InnerGetSchema)
|
|
118
118
|
// k_dl_000001:DB 连接 / QPS 限流 等基础设施层错误
|
|
119
119
|
k_dl_000001: {
|
|
120
|
-
code:
|
|
121
|
-
hint:
|
|
120
|
+
code: 'INTERNAL_DB_ERROR',
|
|
121
|
+
hint: '检查 dbBranch 与应用 PG 实例状态,或稍后重试',
|
|
122
122
|
},
|
|
123
123
|
// k_dl_000002:SQL 解析 / 不支持的 SQL 类型(VACUUM、COPY、SET、SHOW 等)
|
|
124
|
-
k_dl_000002: { code:
|
|
124
|
+
k_dl_000002: { code: 'SQL_SYNTAX_ERROR' },
|
|
125
125
|
// k_dl_000003:查询命中系统表(pg_tables / pg_user 等)被拒
|
|
126
|
-
k_dl_000003: { code:
|
|
126
|
+
k_dl_000003: { code: 'SQL_OPERATION_FORBIDDEN' },
|
|
127
127
|
// k_dl_1300002:PG 执行错误;实际 SQLSTATE 由 extractSqlstate 单独映射
|
|
128
128
|
// 未匹配到 SQLSTATE 时走下面兜底 DB_API_<code>
|
|
129
129
|
// k_dl_1300015:SELECT 结果超过 1000 行硬拦;多行 hint 由 output.ts 的
|
|
130
130
|
// SERVER_ERROR_HINTS 按语义 code 兜底,这里只做 code 改名
|
|
131
|
-
k_dl_1300015: { code:
|
|
131
|
+
k_dl_1300015: { code: 'RESULT_SET_TOO_LARGE' },
|
|
132
|
+
// audit
|
|
133
|
+
k_dl_1310001: {
|
|
134
|
+
code: 'AUDIT_ALREADY_ENABLED',
|
|
135
|
+
hint: 'Use `miaoda db audit status <table>` to confirm current state.',
|
|
136
|
+
},
|
|
137
|
+
k_dl_1310002: {
|
|
138
|
+
code: 'AUDIT_NOT_ENABLED',
|
|
139
|
+
hint: 'Run `miaoda db audit enable <table>` first.',
|
|
140
|
+
},
|
|
141
|
+
k_dl_1310003: {
|
|
142
|
+
code: 'INVALID_RETENTION',
|
|
143
|
+
hint: 'Allowed values: 7d, 30d, 180d, 360d, forever.',
|
|
144
|
+
},
|
|
145
|
+
// migration
|
|
146
|
+
k_dl_1320001: {
|
|
147
|
+
code: 'MIGRATION_NOT_AVAILABLE',
|
|
148
|
+
hint: 'Migration commands require an expert-mode application.',
|
|
149
|
+
},
|
|
150
|
+
k_dl_1320002: { code: 'MULTI_ENV_ALREADY_INITIALIZED' },
|
|
151
|
+
k_dl_1320003: {
|
|
152
|
+
code: 'NO_PENDING_CHANGES',
|
|
153
|
+
hint: 'dev and online schemas are already in sync.',
|
|
154
|
+
},
|
|
155
|
+
// recovery
|
|
156
|
+
k_dl_1330001: {
|
|
157
|
+
code: 'RECOVERY_WINDOW_EXCEEDED',
|
|
158
|
+
hint: 'Pick a timestamp inside the supported recovery window.',
|
|
159
|
+
},
|
|
160
|
+
k_dl_1330002: {
|
|
161
|
+
code: 'RECOVERY_IN_PROGRESS',
|
|
162
|
+
hint: 'Wait for the running recovery to finish, or check its status.',
|
|
163
|
+
},
|
|
164
|
+
k_dl_1330003: {
|
|
165
|
+
code: 'INVALID_TIMESTAMP',
|
|
166
|
+
hint: 'Use ISO 8601 / yyyy-mm-dd / yyyy-mm-dd HH:MM:SS.',
|
|
167
|
+
},
|
|
132
168
|
}));
|
|
133
169
|
/** PG SQLSTATE → CLI code(当前 dataloom 不一定透传,预留未来使用) */
|
|
134
170
|
exports.SQLSTATE_MAP = {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
171
|
+
'42601': 'SQL_SYNTAX_ERROR',
|
|
172
|
+
'42P01': 'TABLE_NOT_FOUND',
|
|
173
|
+
'42703': 'COLUMN_NOT_FOUND',
|
|
174
|
+
'57014': 'STATEMENT_TIMEOUT',
|
|
175
|
+
'23505': 'UNIQUE_VIOLATION',
|
|
176
|
+
'22P02': 'TYPE_MISMATCH',
|
|
141
177
|
};
|
|
142
178
|
/**
|
|
143
179
|
* 从 envelope 里取 data 业务字段,校验成功后返回;失败则 throw。
|
|
@@ -145,7 +181,7 @@ exports.SQLSTATE_MAP = {
|
|
|
145
181
|
function extractData(body) {
|
|
146
182
|
ensureInnerSuccess(body);
|
|
147
183
|
if (!body?.data) {
|
|
148
|
-
throw new error_1.AppError(
|
|
184
|
+
throw new error_1.AppError('INTERNAL_DB_ERROR', 'response missing data field');
|
|
149
185
|
}
|
|
150
186
|
return body.data;
|
|
151
187
|
}
|
|
@@ -161,13 +197,17 @@ function extractData(body) {
|
|
|
161
197
|
* 调用方传入的 path 已包含 `/db` / `/data` 中段,这里只负责拼前缀和 query。
|
|
162
198
|
*/
|
|
163
199
|
function buildInnerUrl(appId, path, query) {
|
|
164
|
-
const normalized = path.startsWith(
|
|
200
|
+
const normalized = path.startsWith('/') ? path : `/${path}`;
|
|
165
201
|
let url = `/v1/dataloom/app/${encodeURIComponent(appId)}${normalized}`;
|
|
166
202
|
if (query) {
|
|
167
203
|
const usp = new URLSearchParams();
|
|
168
204
|
for (const [k, v] of Object.entries(query)) {
|
|
169
|
-
if (v
|
|
170
|
-
|
|
205
|
+
if (v === undefined || v === '')
|
|
206
|
+
continue;
|
|
207
|
+
// dbBranch 兼容用户视角的 `online` 别名 → 后端实际 dbBranch 名为 `main`,
|
|
208
|
+
// 这里集中归一,避免每个 API 函数各自处理。其他值(dev / 自定义分支)原样透传。
|
|
209
|
+
const norm = k === 'dbBranch' && v === 'online' ? 'main' : v;
|
|
210
|
+
usp.append(k, norm);
|
|
171
211
|
}
|
|
172
212
|
const qs = usp.toString();
|
|
173
213
|
if (qs)
|
package/dist/api/db/index.js
CHANGED
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.pickTableDetail = exports.flattenSchemaList = exports.parseSqlResult = exports.SQLSTATE_MAP = exports.ensureInnerSuccess = exports.buildInnerUrl = exports.exportData = exports.importData = exports.getSchema = exports.execSql = void 0;
|
|
3
|
+
exports.pickTableDetail = exports.flattenSchemaList = exports.parseSqlResult = exports.SQLSTATE_MAP = exports.ensureInnerSuccess = exports.buildInnerUrl = exports.getDbQuota = exports.getRecoveryStatus = exports.getRecoveryPreview = exports.recover = exports.getMigrationStatus = exports.migrate = exports.migrationInit = exports.listAuditLog = exports.setAuditConfig = exports.getAuditStatus = exports.listDDLChangelog = exports.exportData = exports.importData = exports.getSchema = exports.execSql = void 0;
|
|
4
4
|
var api_1 = require("./api");
|
|
5
5
|
Object.defineProperty(exports, "execSql", { enumerable: true, get: function () { return api_1.execSql; } });
|
|
6
6
|
Object.defineProperty(exports, "getSchema", { enumerable: true, get: function () { return api_1.getSchema; } });
|
|
7
7
|
Object.defineProperty(exports, "importData", { enumerable: true, get: function () { return api_1.importData; } });
|
|
8
8
|
Object.defineProperty(exports, "exportData", { enumerable: true, get: function () { return api_1.exportData; } });
|
|
9
|
+
Object.defineProperty(exports, "listDDLChangelog", { enumerable: true, get: function () { return api_1.listDDLChangelog; } });
|
|
10
|
+
Object.defineProperty(exports, "getAuditStatus", { enumerable: true, get: function () { return api_1.getAuditStatus; } });
|
|
11
|
+
Object.defineProperty(exports, "setAuditConfig", { enumerable: true, get: function () { return api_1.setAuditConfig; } });
|
|
12
|
+
Object.defineProperty(exports, "listAuditLog", { enumerable: true, get: function () { return api_1.listAuditLog; } });
|
|
13
|
+
Object.defineProperty(exports, "migrationInit", { enumerable: true, get: function () { return api_1.migrationInit; } });
|
|
14
|
+
Object.defineProperty(exports, "migrate", { enumerable: true, get: function () { return api_1.migrate; } });
|
|
15
|
+
Object.defineProperty(exports, "getMigrationStatus", { enumerable: true, get: function () { return api_1.getMigrationStatus; } });
|
|
16
|
+
Object.defineProperty(exports, "recover", { enumerable: true, get: function () { return api_1.recover; } });
|
|
17
|
+
Object.defineProperty(exports, "getRecoveryPreview", { enumerable: true, get: function () { return api_1.getRecoveryPreview; } });
|
|
18
|
+
Object.defineProperty(exports, "getRecoveryStatus", { enumerable: true, get: function () { return api_1.getRecoveryStatus; } });
|
|
19
|
+
Object.defineProperty(exports, "getDbQuota", { enumerable: true, get: function () { return api_1.getDbQuota; } });
|
|
9
20
|
var client_1 = require("./client");
|
|
10
21
|
Object.defineProperty(exports, "buildInnerUrl", { enumerable: true, get: function () { return client_1.buildInnerUrl; } });
|
|
11
22
|
Object.defineProperty(exports, "ensureInnerSuccess", { enumerable: true, get: function () { return client_1.ensureInnerSuccess; } });
|
package/dist/api/db/parsers.js
CHANGED
|
@@ -9,7 +9,7 @@ const error_1 = require("../../utils/error");
|
|
|
9
9
|
* 解析 InnerExecuteSQL 的单条 results[](PRD 要求多条语句只取最后一条)。
|
|
10
10
|
*/
|
|
11
11
|
function parseSqlResult(r) {
|
|
12
|
-
if (r.sqlType ===
|
|
12
|
+
if (r.sqlType === 'SELECT') {
|
|
13
13
|
let rows = [];
|
|
14
14
|
if (r.data) {
|
|
15
15
|
try {
|
|
@@ -18,23 +18,23 @@ function parseSqlResult(r) {
|
|
|
18
18
|
rows = parsed;
|
|
19
19
|
}
|
|
20
20
|
catch {
|
|
21
|
-
throw new error_1.AppError(
|
|
21
|
+
throw new error_1.AppError('INTERNAL_DB_ERROR', 'Failed to parse SELECT result JSON');
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
return {
|
|
25
|
-
kind:
|
|
25
|
+
kind: 'select',
|
|
26
26
|
rows,
|
|
27
27
|
recordCount: r.recordCount ?? rows.length,
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
|
-
if (r.sqlType ===
|
|
31
|
-
r.sqlType ===
|
|
32
|
-
r.sqlType ===
|
|
33
|
-
r.sqlType ===
|
|
34
|
-
r.sqlType ===
|
|
30
|
+
if (r.sqlType === 'INSERT' ||
|
|
31
|
+
r.sqlType === 'UPDATE' ||
|
|
32
|
+
r.sqlType === 'DELETE' ||
|
|
33
|
+
r.sqlType === 'MERGE' ||
|
|
34
|
+
r.sqlType === 'DML') {
|
|
35
35
|
const affected = r.affectedRows ?? extractRowCount(r.data);
|
|
36
36
|
return {
|
|
37
|
-
kind:
|
|
37
|
+
kind: 'dml',
|
|
38
38
|
// 上面已 narrow,这里 cast 是为了 SqlType 联合里的 (string & {}) 让 TS 无法
|
|
39
39
|
// 自动收窄到字面量集合,不影响运行时安全
|
|
40
40
|
sqlType: r.sqlType,
|
|
@@ -43,7 +43,7 @@ function parseSqlResult(r) {
|
|
|
43
43
|
}
|
|
44
44
|
// DDL or unknown — sqlType 透传后端给的细粒度(CREATE_TABLE / DROP_TABLE / ...
|
|
45
45
|
// / 笼统 "DDL"),CLI JSON 输出直接当 command 用
|
|
46
|
-
return { kind:
|
|
46
|
+
return { kind: 'ddl', sqlType: r.sqlType };
|
|
47
47
|
}
|
|
48
48
|
/** DML 的 data 通常是 `[{"rowCount": N}]`;兜底从这里读影响行数。 */
|
|
49
49
|
function extractRowCount(data) {
|
|
@@ -54,7 +54,7 @@ function extractRowCount(data) {
|
|
|
54
54
|
if (Array.isArray(parsed) && parsed.length > 0) {
|
|
55
55
|
const first = parsed[0];
|
|
56
56
|
const v = first.rowCount ?? first.affected_rows;
|
|
57
|
-
if (typeof v ===
|
|
57
|
+
if (typeof v === 'number')
|
|
58
58
|
return v;
|
|
59
59
|
}
|
|
60
60
|
}
|
|
@@ -87,8 +87,8 @@ function toSummary(t, stats) {
|
|
|
87
87
|
name: t.tableName,
|
|
88
88
|
description: t.comment && t.comment.length > 0 ? t.comment : null,
|
|
89
89
|
columns: (t.fields ?? []).length,
|
|
90
|
-
estimated_row_count: typeof stats?.estimatedRowCount ===
|
|
91
|
-
size_bytes: typeof stats?.sizeBytes ===
|
|
90
|
+
estimated_row_count: typeof stats?.estimatedRowCount === 'number' ? stats.estimatedRowCount : null,
|
|
91
|
+
size_bytes: typeof stats?.sizeBytes === 'number' ? stats.sizeBytes : null,
|
|
92
92
|
};
|
|
93
93
|
}
|
|
94
94
|
/**
|
|
@@ -125,18 +125,18 @@ function toDetail(t, stats) {
|
|
|
125
125
|
if (cols.length === 0)
|
|
126
126
|
continue;
|
|
127
127
|
const kind = i.indexType.toLowerCase();
|
|
128
|
-
if (kind ===
|
|
129
|
-
constraints.push({ type:
|
|
128
|
+
if (kind === 'primary') {
|
|
129
|
+
constraints.push({ type: 'PRIMARY KEY', columns: cols });
|
|
130
130
|
}
|
|
131
|
-
else if (kind ===
|
|
132
|
-
constraints.push({ type:
|
|
131
|
+
else if (kind === 'unique') {
|
|
132
|
+
constraints.push({ type: 'UNIQUE', columns: cols });
|
|
133
133
|
}
|
|
134
134
|
else {
|
|
135
135
|
// foreign / normal / 其它统一进 indexes 段;method 从 indexDef 的 USING 段解析
|
|
136
136
|
indexes.push({
|
|
137
137
|
name: i.indexName,
|
|
138
138
|
columns: cols,
|
|
139
|
-
method: parseIndexMethod(i.indexDef) ??
|
|
139
|
+
method: parseIndexMethod(i.indexDef) ?? 'btree',
|
|
140
140
|
});
|
|
141
141
|
}
|
|
142
142
|
}
|
|
@@ -146,8 +146,8 @@ function toDetail(t, stats) {
|
|
|
146
146
|
columns: (t.fields ?? []).map(toColumn),
|
|
147
147
|
constraints,
|
|
148
148
|
indexes,
|
|
149
|
-
estimated_row_count: typeof stats?.estimatedRowCount ===
|
|
150
|
-
size_bytes: typeof stats?.sizeBytes ===
|
|
149
|
+
estimated_row_count: typeof stats?.estimatedRowCount === 'number' ? stats.estimatedRowCount : null,
|
|
150
|
+
size_bytes: typeof stats?.sizeBytes === 'number' ? stats.sizeBytes : null,
|
|
151
151
|
};
|
|
152
152
|
}
|
|
153
153
|
function toColumn(f) {
|
|
@@ -21,103 +21,103 @@ exports.SQL_KEYWORDS = void 0;
|
|
|
21
21
|
*/
|
|
22
22
|
exports.SQL_KEYWORDS = [
|
|
23
23
|
// DML 动词
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
'SELECT',
|
|
25
|
+
'INSERT',
|
|
26
|
+
'UPDATE',
|
|
27
|
+
'DELETE',
|
|
28
|
+
'MERGE',
|
|
29
29
|
// FROM / JOIN 系列
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
30
|
+
'FROM',
|
|
31
|
+
'WHERE',
|
|
32
|
+
'JOIN',
|
|
33
|
+
'LEFT',
|
|
34
|
+
'RIGHT',
|
|
35
|
+
'INNER',
|
|
36
|
+
'OUTER',
|
|
37
|
+
'FULL',
|
|
38
|
+
'CROSS',
|
|
39
|
+
'USING',
|
|
40
40
|
// 聚合 / 排序 / 分页
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
41
|
+
'GROUP',
|
|
42
|
+
'ORDER',
|
|
43
|
+
'BY',
|
|
44
|
+
'HAVING',
|
|
45
|
+
'LIMIT',
|
|
46
|
+
'OFFSET',
|
|
47
|
+
'FETCH',
|
|
48
48
|
// 集合操作
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
'UNION',
|
|
50
|
+
'INTERSECT',
|
|
51
|
+
'EXCEPT',
|
|
52
|
+
'DISTINCT',
|
|
53
|
+
'ALL',
|
|
54
54
|
// 别名 / 关联
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
'AS',
|
|
56
|
+
'ON',
|
|
57
57
|
// 操作符词
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
58
|
+
'AND',
|
|
59
|
+
'OR',
|
|
60
|
+
'NOT',
|
|
61
|
+
'IN',
|
|
62
|
+
'IS',
|
|
63
|
+
'NULL',
|
|
64
|
+
'TRUE',
|
|
65
|
+
'FALSE',
|
|
66
|
+
'BETWEEN',
|
|
67
|
+
'LIKE',
|
|
68
|
+
'ILIKE',
|
|
69
|
+
'SIMILAR',
|
|
70
70
|
// DDL
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
71
|
+
'CREATE',
|
|
72
|
+
'ALTER',
|
|
73
|
+
'DROP',
|
|
74
|
+
'TRUNCATE',
|
|
75
|
+
'RENAME',
|
|
76
|
+
'TABLE',
|
|
77
|
+
'INDEX',
|
|
78
|
+
'VIEW',
|
|
79
|
+
'DATABASE',
|
|
80
|
+
'SCHEMA',
|
|
81
|
+
'COLUMN',
|
|
82
|
+
'CONSTRAINT',
|
|
83
|
+
'SEQUENCE',
|
|
84
84
|
// 约束
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
85
|
+
'PRIMARY',
|
|
86
|
+
'KEY',
|
|
87
|
+
'FOREIGN',
|
|
88
|
+
'REFERENCES',
|
|
89
|
+
'UNIQUE',
|
|
90
|
+
'CHECK',
|
|
91
|
+
'DEFAULT',
|
|
92
92
|
// 写入
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
'VALUES',
|
|
94
|
+
'SET',
|
|
95
|
+
'RETURNING',
|
|
96
|
+
'INTO',
|
|
97
97
|
// 事务
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
98
|
+
'BEGIN',
|
|
99
|
+
'COMMIT',
|
|
100
|
+
'ROLLBACK',
|
|
101
|
+
'SAVEPOINT',
|
|
102
|
+
'TRANSACTION',
|
|
103
103
|
// 控制流 / CTE
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
104
|
+
'IF',
|
|
105
|
+
'EXISTS',
|
|
106
|
+
'REPLACE',
|
|
107
|
+
'WITH',
|
|
108
|
+
'RECURSIVE',
|
|
109
|
+
'CASE',
|
|
110
|
+
'WHEN',
|
|
111
|
+
'THEN',
|
|
112
|
+
'ELSE',
|
|
113
|
+
'END',
|
|
114
114
|
// 类型转换 / 时间提取
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
'CAST',
|
|
116
|
+
'EXTRACT',
|
|
117
117
|
// 排序方向
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
118
|
+
'ASC',
|
|
119
|
+
'DESC',
|
|
120
|
+
'NULLS',
|
|
121
|
+
'FIRST',
|
|
122
|
+
'LAST',
|
|
123
123
|
];
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createRelease = createRelease;
|
|
4
|
+
exports.listPipelineInstances = listPipelineInstances;
|
|
5
|
+
exports.getErrorLog = getErrorLog;
|
|
6
|
+
exports.queryPipelineInstance = queryPipelineInstance;
|
|
7
|
+
const http_1 = require("../../utils/http");
|
|
8
|
+
const devops_error_1 = require("../../utils/devops-error");
|
|
9
|
+
const DEFAULT_ERR_CODE = 'INTERNAL_DEVOPS_ERROR';
|
|
10
|
+
function envelopeOpts(errPrefix) {
|
|
11
|
+
return {
|
|
12
|
+
errPrefix,
|
|
13
|
+
defaultErrCode: DEFAULT_ERR_CODE,
|
|
14
|
+
// deploy 与 app 走同一个 PSM;业务码映射复用
|
|
15
|
+
mapErr: devops_error_1.mapDevopsError,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/** POST /v1/devops/app/:appID/release — 触发发布 */
|
|
19
|
+
async function createRelease(req) {
|
|
20
|
+
const url = `/v1/devops/app/${encodeURIComponent(req.appID)}/release`;
|
|
21
|
+
return (0, http_1.postInnerApi)(url, req, envelopeOpts('Failed to create release'));
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* POST /v1/pipeline/app/:appID/instance/list — 分页查询发布历史
|
|
25
|
+
*
|
|
26
|
+
* 走 lark.apaas.devops_platform PSM(同 queryPipelineInstance)。
|
|
27
|
+
* 不复用 mapDevopsError——那是 lark.apaas.devops 的业务码映射。
|
|
28
|
+
*/
|
|
29
|
+
async function listPipelineInstances(req) {
|
|
30
|
+
const url = `/v1/pipeline/app/${encodeURIComponent(req.appID)}/instance/list`;
|
|
31
|
+
return (0, http_1.postInnerApi)(url, req, {
|
|
32
|
+
errPrefix: 'Failed to list deploys',
|
|
33
|
+
defaultErrCode: DEFAULT_ERR_CODE,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* GET /v1/pipeline/app/:appID/instance/:instanceID/error_log — 获取发布错误日志
|
|
38
|
+
*
|
|
39
|
+
* 走 lark.apaas.devops_platform PSM;instanceID 即 pipelineTaskID == deploy-id。
|
|
40
|
+
* BAM CliGetToolInstanceErrorJobs(4073972),路径段无 body。
|
|
41
|
+
*/
|
|
42
|
+
async function getErrorLog(req) {
|
|
43
|
+
const url = `/v1/pipeline/app/${encodeURIComponent(req.appID)}/instance/${encodeURIComponent(req.instanceID)}/error_log`;
|
|
44
|
+
return (0, http_1.getInnerApi)(url, {
|
|
45
|
+
errPrefix: 'Failed to get error log',
|
|
46
|
+
defaultErrCode: DEFAULT_ERR_CODE,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* GET /v1/pipeline/app/:appID/instance/:instanceID/detail — 轮询发布状态
|
|
51
|
+
*
|
|
52
|
+
* 走 lark.apaas.devops_platform PSM;URL 前缀不同但共用同一管理端 gateway。
|
|
53
|
+
*/
|
|
54
|
+
async function queryPipelineInstance(req) {
|
|
55
|
+
const url = `/v1/pipeline/app/${encodeURIComponent(req.appID)}/instance/${encodeURIComponent(req.instanceID)}/detail`;
|
|
56
|
+
return (0, http_1.getInnerApi)(url, {
|
|
57
|
+
errPrefix: 'Failed to query pipeline',
|
|
58
|
+
defaultErrCode: DEFAULT_ERR_CODE,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NodeStatus = exports.nodeStatusFromText = exports.nodeStatusText = exports.errorJobSchema = exports.deployGetSchema = exports.deployHistorySchema = exports.queryPipelineInstance = exports.getErrorLog = exports.listPipelineInstances = exports.createRelease = void 0;
|
|
4
|
+
var api_1 = require("./api");
|
|
5
|
+
Object.defineProperty(exports, "createRelease", { enumerable: true, get: function () { return api_1.createRelease; } });
|
|
6
|
+
Object.defineProperty(exports, "listPipelineInstances", { enumerable: true, get: function () { return api_1.listPipelineInstances; } });
|
|
7
|
+
Object.defineProperty(exports, "getErrorLog", { enumerable: true, get: function () { return api_1.getErrorLog; } });
|
|
8
|
+
Object.defineProperty(exports, "queryPipelineInstance", { enumerable: true, get: function () { return api_1.queryPipelineInstance; } });
|
|
9
|
+
var schemas_1 = require("./schemas");
|
|
10
|
+
Object.defineProperty(exports, "deployHistorySchema", { enumerable: true, get: function () { return schemas_1.deployHistorySchema; } });
|
|
11
|
+
Object.defineProperty(exports, "deployGetSchema", { enumerable: true, get: function () { return schemas_1.deployGetSchema; } });
|
|
12
|
+
Object.defineProperty(exports, "errorJobSchema", { enumerable: true, get: function () { return schemas_1.errorJobSchema; } });
|
|
13
|
+
Object.defineProperty(exports, "nodeStatusText", { enumerable: true, get: function () { return schemas_1.nodeStatusText; } });
|
|
14
|
+
Object.defineProperty(exports, "nodeStatusFromText", { enumerable: true, get: function () { return schemas_1.nodeStatusFromText; } });
|
|
15
|
+
var types_1 = require("./types");
|
|
16
|
+
Object.defineProperty(exports, "NodeStatus", { enumerable: true, get: function () { return types_1.NodeStatus; } });
|