合并 tjwater-cli 到 main #1
@@ -14,7 +14,7 @@ export default tool({
|
|||||||
command: tool.schema
|
command: tool.schema
|
||||||
.string()
|
.string()
|
||||||
.describe(
|
.describe(
|
||||||
"tjwater-cli 子命令,不含二进制路径。示例:'project list'、'data timeseries realtime links --start-time 2025-01-01T00:00:00+08:00 --end-time 2025-01-01T01:00:00+08:00'",
|
"tjwater-cli 子命令,不含二进制路径。示例:'data scheme list'、'data timeseries realtime links --start-time 2025-01-01T00:00:00+08:00 --end-time 2025-01-01T01:00:00+08:00'",
|
||||||
),
|
),
|
||||||
timeout: tool.schema
|
timeout: tool.schema
|
||||||
.number()
|
.number()
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ import { resolveScheme } from "../core/runtime.js";
|
|||||||
import { parseTime } from "../core/time.js";
|
import { parseTime } from "../core/time.js";
|
||||||
import type { HandlerMap, RuntimeContext } from "../core/types.js";
|
import type { HandlerMap, RuntimeContext } from "../core/types.js";
|
||||||
|
|
||||||
|
function backendElementType(type: ElementType): "link" | "node" {
|
||||||
|
return type === "pipe" ? "link" : "node";
|
||||||
|
}
|
||||||
|
|
||||||
function rangeGet(ctx: RuntimeContext, argv: string[], summary: string, path: string): Promise<void> {
|
function rangeGet(ctx: RuntimeContext, argv: string[], summary: string, path: string): Promise<void> {
|
||||||
const { values } = parseOptions(argv);
|
const { values } = parseOptions(argv);
|
||||||
return emitApi(ctx, summary, {
|
return emitApi(ctx, summary, {
|
||||||
@@ -18,10 +22,11 @@ function rangeGet(ctx: RuntimeContext, argv: string[], summary: string, path: st
|
|||||||
|
|
||||||
function realtimeByIdTime(ctx: RuntimeContext, argv: string[]): Promise<void> {
|
function realtimeByIdTime(ctx: RuntimeContext, argv: string[]): Promise<void> {
|
||||||
const { values } = parseOptions(argv);
|
const { values } = parseOptions(argv);
|
||||||
|
const type = validateChoice(requiredString(values, "type"), ["pipe", "junction"] as const, "--type");
|
||||||
return emitApi(ctx, "读取实时模拟数据成功", {
|
return emitApi(ctx, "读取实时模拟数据成功", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
path: "/timeseries/realtime/simulation-results",
|
path: "/timeseries/realtime/simulation-results",
|
||||||
params: { id: requiredString(values, "id"), type: validateChoice(requiredString(values, "type"), ["pipe", "junction"] as const, "--type"), query_time: parseTime(requiredString(values, "time"), "--time") },
|
params: { id: requiredString(values, "id"), type: backendElementType(type), query_time: parseTime(requiredString(values, "time"), "--time") },
|
||||||
requireProject: true,
|
requireProject: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -32,7 +37,7 @@ function realtimeByTimeProperty(ctx: RuntimeContext, argv: string[]): Promise<vo
|
|||||||
return emitApi(ctx, "读取实时属性聚合数据成功", {
|
return emitApi(ctx, "读取实时属性聚合数据成功", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
path: "/timeseries/realtime/records",
|
path: "/timeseries/realtime/records",
|
||||||
params: { type, query_time: parseTime(requiredString(values, "time"), "--time"), property: validateChoice(requiredString(values, "property"), fieldsFor(type), "--property") },
|
params: { type: backendElementType(type), query_time: parseTime(requiredString(values, "time"), "--time"), property: validateChoice(requiredString(values, "property"), fieldsFor(type), "--property") },
|
||||||
requireProject: true,
|
requireProject: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -76,7 +81,7 @@ function schemeSimulation(ctx: RuntimeContext, argv: string[]): Promise<void> {
|
|||||||
scheme_name: resolveScheme(ctx, optionalString(values, "scheme"), true),
|
scheme_name: resolveScheme(ctx, optionalString(values, "scheme"), true),
|
||||||
scheme_type: optionalString(values, "scheme-type") || "simulation",
|
scheme_type: optionalString(values, "scheme-type") || "simulation",
|
||||||
query_time: parseTime(requiredString(values, "time"), "--time"),
|
query_time: parseTime(requiredString(values, "time"), "--time"),
|
||||||
type,
|
type: backendElementType(type),
|
||||||
};
|
};
|
||||||
if (query === "by-id-time") {
|
if (query === "by-id-time") {
|
||||||
params.id = requiredString(values, "id");
|
params.id = requiredString(values, "id");
|
||||||
|
|||||||
@@ -262,6 +262,26 @@ test("uses project scoped headers for realtime data commands", async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("maps CLI pipe and junction types to backend link and node types", async () => {
|
||||||
|
const server = await startJsonServer({ accepted: true });
|
||||||
|
const auth = { server: server.url, access_token: "token-3", project_id: "project-1" };
|
||||||
|
const at = "2025-01-02T03:30:00+08:00";
|
||||||
|
try {
|
||||||
|
for (const args of [
|
||||||
|
["data", "timeseries", "realtime", "simulation-by-id-time", "--id", "J1", "--type", "junction", "--time", at],
|
||||||
|
["data", "timeseries", "realtime", "simulation-by-time-property", "--type", "pipe", "--time", at, "--property", "flow"],
|
||||||
|
["data", "timeseries", "scheme", "simulation", "--query", "by-id-time", "--id", "P1", "--type", "pipe", "--time", at, "--scheme", "scheme_case"],
|
||||||
|
]) {
|
||||||
|
const result = await runCli(["--auth-stdin", ...args], auth);
|
||||||
|
assert.equal(result.exitCode, 0, result.stderr);
|
||||||
|
}
|
||||||
|
const queries = server.seen.map(normalizeSeenRequest).map((request) => request.query.type);
|
||||||
|
assert.deepEqual(queries, ["node", "link", "link"]);
|
||||||
|
} finally {
|
||||||
|
await server.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test("matches Python CLI backend request shape for every command and key variants", async () => {
|
test("matches Python CLI backend request shape for every command and key variants", async () => {
|
||||||
const tempDir = await mkdtemp(join(tmpdir(), "tjwater-cli-parity-"));
|
const tempDir = await mkdtemp(join(tmpdir(), "tjwater-cli-parity-"));
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user