From 3fd75a25cca49ce1e262480e53102fe337552c92 Mon Sep 17 00:00:00 2001
From: Marin Karamihalev <marin.karamihalev@iopsys.eu>
Date: Wed, 23 Nov 2022 14:06:03 +0100
Subject: [PATCH] fixed get call with query bug, improved __query__ for nested
 query calls, resolved minor get property bug

---
 src/commands/util.ts            | 24 +++++++++++++++++-------
 src/types.ts                    |  3 +++
 tests/integration/index.test.ts |  9 ++++-----
 3 files changed, 24 insertions(+), 12 deletions(-)

diff --git a/src/commands/util.ts b/src/commands/util.ts
index 3891815..f1a2f2a 100644
--- a/src/commands/util.ts
+++ b/src/commands/util.ts
@@ -1,7 +1,6 @@
 import {
   CommandType,
   DecodeOptions,
-  GetNestedReturn,
   UspProperty,
   UspPropertyList,
 } from "../types";
@@ -188,6 +187,8 @@ export const parseID = (msg: any) => {
 const grab = (item: any, key: string) =>
   Array.isArray(item)
     ? item.find((val) => val !== null && val !== undefined)
+    : key === "-1"
+    ? item.find((v) => v !== null)
     : item[key];
 const skipKeys = (obj: any, keys: string[]) =>
   keys.length === 1
@@ -237,6 +238,13 @@ const addQueries = (obj: any, path: string) =>
         ),
       };
 
+const locatePath = (result: PathResult): string =>
+  result.resolvedPathResults?.reduce((shortestRes, currentRes) =>
+    currentRes.resolvedPath.length < shortestRes.resolvedPath.length
+      ? currentRes
+      : shortestRes
+  ).resolvedPath || result.requestedPath;
+
 export const processGetResult = (
   reqPathResults: PathResult[],
   decodeOptions?: DecodeOptions
@@ -273,16 +281,18 @@ export const processGetResult = (
       respType === ResponseType.Object ||
       respType === ResponseType.ObjectList
     ) {
-      const mainObject = skipKeys(
-        convertToNestedObject(results),
-        resolvedResult.requestedPath.split(".").slice(0, -1)
-      );
+      const actualPath = containsQuery(resolvedResult.requestedPath)
+        ? locatePath(resolvedResult)
+        : resolvedResult.requestedPath;
+      const keys = actualPath.split(".").slice(0, -1);
+      const nestedObject = convertToNestedObject(results);
+      const mainObject = skipKeys(nestedObject, keys);
       const cleanedObject = removeNulls(mainObject);
       return !retainPath
         ? cleanedObject
         : {
             __query__: resolvedResult.requestedPath,
-            result: addQueries(mainObject, resolvedResult.requestedPath),
+            result: addQueries(mainObject, actualPath),
           };
     }
 
@@ -312,7 +322,7 @@ export enum ResponseType {
 const containsQuery = (path: string): boolean =>
   path.split(".").some((part) => part.includes("*") || part.includes("["));
 const endsWithProperty = (path: string): boolean =>
-  /^.+\.[A-Za-z]+$/.test(path);
+  /^.+\.[A-Za-z0-9]+$/.test(path);
 const endsWithIndex = (path: string): boolean => /^.+\.\d+\.$/.test(path);
 const endsWithIndexedProperty = (path: string): boolean =>
   /^.+\.\d+\..+$/.test(path.split(".").slice(-2)[0]);
diff --git a/src/types.ts b/src/types.ts
index 3ff8869..804fd55 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -433,6 +433,9 @@ export interface USP {
    * const [ping, cleanPing] = await usp.operate("Device.IP.Diagnostics.IPPing()")
    * const results = await ping({ Host: "iopsys.eu" })
    * await cleanPing()
+   * // sync command example, no need to get cleanup function as there is nothing to clean up with sync commands
+   * const [op] = await device.operate("Device.WiFi.Reset()", { isAsync: false })
+   * await op().then(log).catch(log)
    * ```
    */
   operate: OperateRecipe;
diff --git a/tests/integration/index.test.ts b/tests/integration/index.test.ts
index d710939..f78c790 100644
--- a/tests/integration/index.test.ts
+++ b/tests/integration/index.test.ts
@@ -62,7 +62,8 @@ describe("Test general API", function () {
         resp.__query__ === "Device.NAT.PortMapping.*.Alias" &&
         Array.isArray(resp.result) &&
         resp.result.every(
-          (v) => "__query__" in v && "result" in v && typeof v.result === "string"
+          (v) =>
+            "__query__" in v && "result" in v && typeof v.result === "string"
         ),
       true
     );
@@ -77,15 +78,13 @@ describe("Test general API", function () {
     );
   });
 
-  it("get an array of object with retainPath returns all objects with paths", async () => {
+  it("get an array of objects with retainPath returns all objects with paths", async () => {
     const resp = await device.getNested("Device.NAT.PortMapping.");
     assert.strictEqual(
       typeof resp.result === "object" &&
         resp.__query__ === "Device.NAT.PortMapping." &&
         Array.isArray(resp.result) &&
-        resp.result.every(
-          (v) => "__query__" in v && "result" in v && typeof v.result === "object"
-        ),
+        resp.result.every((v) => "__query__" in v),
       true
     );
   });
-- 
GitLab