using System.Text.Json; using System.Text.Json.Nodes; namespace ZB.MOM.WW.ScadaBridge.CLI.Commands; /// /// Compact table projection for template list / template get. /// /// /// template get returns a full Template entity — every attribute, alarm, /// script, and composition inline — which the generic table renderer dumps as one giant /// cell per template (~171 KB for a real catalogue, unusable in a terminal). /// template list no longer returns entities at all: the management /// ListTemplates handler projects in the DATABASE and returns /// TemplateSummary rows whose children are already reduced to /// attributeCount/alarmCount/… scalars. /// /// /// /// This projector handles BOTH shapes: it prefers the pre-computed *Count /// scalar and falls back to the length of the matching child array, so the same /// column set renders for a summary row and for a full entity. Reading only the /// arrays (as it originally did) made template list print a wall of zeros /// once the server switched to summaries. /// /// /// /// JSON output is left untouched (callers pass this only on the table path), and /// the command's --detail flag skips the projection to render the raw /// payload as-is. /// /// internal static class TemplateTableProjection { /// /// Projects a templates JSON response (an array from list or a single object /// from get) to its compact summary form. Returns the input unchanged when it /// is not JSON or not the expected shape, so the generic renderer's own fallbacks /// still apply. /// /// The raw success JSON body from the management API. /// Compact JSON (same array/object shape) suitable for table rendering. internal static string ProjectSummary(string json) { JsonDocument doc; try { doc = JsonDocument.Parse(json); } catch (JsonException) { // Not JSON (e.g. a proxy error page) — let the renderer print it verbatim. return json; } using (doc) { var root = doc.RootElement; if (root.ValueKind == JsonValueKind.Array) { var arr = new JsonArray(); foreach (var item in root.EnumerateArray()) arr.Add(ProjectElement(item)); return arr.ToJsonString(); } if (root.ValueKind == JsonValueKind.Object) { return ProjectElement(root).ToJsonString(); } return json; } } /// Projects a single template object to its compact summary node. private static JsonNode ProjectElement(JsonElement element) { if (element.ValueKind != JsonValueKind.Object) return JsonValue.Create(element.ToString())!; // JsonObject preserves insertion order, fixing the column order for the table. return new JsonObject { ["id"] = Int(element, "id"), ["name"] = Str(element, "name"), ["description"] = Str(element, "description"), ["parentTemplateId"] = Int(element, "parentTemplateId"), ["isDerived"] = Bool(element, "isDerived"), ["#attrs"] = Count(element, "attributeCount", "attributes"), ["#alarms"] = Count(element, "alarmCount", "alarms"), ["#scripts"] = Count(element, "scriptCount", "scripts"), ["#comps"] = Count(element, "compositionCount", "compositions"), ["#nativeAlarms"] = Count(element, "nativeAlarmSourceCount", "nativeAlarmSources"), }; } private static bool TryGetPropertyCI(JsonElement obj, string name, out JsonElement value) { foreach (var prop in obj.EnumerateObject()) { if (string.Equals(prop.Name, name, StringComparison.OrdinalIgnoreCase)) { value = prop.Value; return true; } } value = default; return false; } private static JsonNode? Str(JsonElement obj, string name) => TryGetPropertyCI(obj, name, out var v) && v.ValueKind == JsonValueKind.String ? JsonValue.Create(v.GetString()) : null; private static JsonNode? Int(JsonElement obj, string name) => TryGetPropertyCI(obj, name, out var v) && v.ValueKind == JsonValueKind.Number && v.TryGetInt32(out var n) ? JsonValue.Create(n) : null; private static JsonNode? Bool(JsonElement obj, string name) => TryGetPropertyCI(obj, name, out var v) && (v.ValueKind == JsonValueKind.True || v.ValueKind == JsonValueKind.False) ? JsonValue.Create(v.GetBoolean()) : null; /// /// Member count for a column, preferring the summary payload's pre-computed /// scalar () and falling back to the length of the /// full entity's child array (). Zero when neither /// is present. /// /// The template object being projected. /// Scalar count property on a TemplateSummary row. /// Child-collection property on a full Template entity. /// The member count as a JSON number. private static JsonNode Count(JsonElement obj, string countName, string arrayName) { if (TryGetPropertyCI(obj, countName, out var scalar) && scalar.ValueKind == JsonValueKind.Number && scalar.TryGetInt32(out var n)) { return JsonValue.Create(n); } return JsonValue.Create( TryGetPropertyCI(obj, arrayName, out var v) && v.ValueKind == JsonValueKind.Array ? v.GetArrayLength() : 0); } }