From 4c11a6593c38c65a897d1e476734cf78ab6f942e Mon Sep 17 00:00:00 2001
From: Adria Navarro <adria@budibase.com>
Date: Mon, 31 Jul 2023 10:43:45 +0200
Subject: [PATCH] Add sdk trim view fields

---
 .../src/sdk/app/rows/tests/utils.spec.ts      | 90 +++++++++++++++++++
 packages/server/src/sdk/app/rows/utils.ts     | 19 ++++
 2 files changed, 109 insertions(+)
 create mode 100644 packages/server/src/sdk/app/rows/tests/utils.spec.ts

diff --git a/packages/server/src/sdk/app/rows/tests/utils.spec.ts b/packages/server/src/sdk/app/rows/tests/utils.spec.ts
new file mode 100644
index 0000000000..18b169ed4f
--- /dev/null
+++ b/packages/server/src/sdk/app/rows/tests/utils.spec.ts
@@ -0,0 +1,90 @@
+import { generator } from "@budibase/backend-core/tests"
+import { FieldType, Table } from "@budibase/types"
+jest.mock("../../../../sdk", () => ({
+  views: {
+    ...jest.requireActual("../../../../sdk/app/views"),
+    get: jest.fn(),
+  },
+}))
+
+import sdk from "../../../../sdk"
+import { trimViewFields } from "../utils"
+
+const mockGetView = sdk.views.get as jest.MockedFunction<typeof sdk.views.get>
+
+describe("utils", () => {
+  const table: Table = {
+    name: generator.word(),
+    type: "table",
+    schema: {
+      name: {
+        name: "name",
+        type: FieldType.STRING,
+      },
+      age: {
+        name: "age",
+        type: FieldType.NUMBER,
+      },
+      address: {
+        name: "address",
+        type: FieldType.STRING,
+      },
+    },
+  }
+
+  beforeEach(() => {
+    jest.resetAllMocks()
+  })
+
+  describe("trimViewFields", () => {
+    it("when no columns are defined, same data is returned", async () => {
+      mockGetView.mockResolvedValue({
+        version: 2,
+        id: generator.guid(),
+        name: generator.guid(),
+        tableId: generator.guid(),
+      })
+
+      const viewId = generator.guid()
+      const data = {
+        _id: generator.guid(),
+        name: generator.name(),
+        age: generator.age(),
+        address: generator.address(),
+      }
+
+      const result = await trimViewFields(viewId, table, data)
+
+      expect(result).toBe(data)
+    })
+
+    it("when columns are defined, trim data is returned", async () => {
+      mockGetView.mockResolvedValue({
+        version: 2,
+        id: generator.guid(),
+        name: generator.guid(),
+        tableId: generator.guid(),
+        columns: {
+          name: { visible: true },
+          address: { visible: true },
+          age: { visible: false },
+        },
+      })
+
+      const viewId = generator.guid()
+      const data = {
+        _id: generator.guid(),
+        name: generator.name(),
+        age: generator.age(),
+        address: generator.address(),
+      }
+
+      const result = await trimViewFields(viewId, table, data)
+
+      expect(result).toEqual({
+        name: data.name,
+        address: data.address,
+      })
+    })
+  })
+})
diff --git a/packages/server/src/sdk/app/rows/utils.ts b/packages/server/src/sdk/app/rows/utils.ts
index 51e418c324..17add1f934 100644
--- a/packages/server/src/sdk/app/rows/utils.ts
+++ b/packages/server/src/sdk/app/rows/utils.ts
@@ -135,3 +135,22 @@ export async function validate({
   }
   return { valid: Object.keys(errors).length === 0, errors }
 }
+
+export async function trimViewFields<T extends Row>(
+  viewId: string,
+  table: Table,
+  data: T
+): Promise<T> {
+  const view = await sdk.views.get(viewId)
+  if (!view?.columns || !Object.keys(view.columns).length) {
+    return data
+  }
+
+  const { schema } = sdk.views.enrichSchema(view!, table.schema)
+  const result: Record<string, any> = {}
+  for (const key of Object.keys(schema)) {
+    result[key] = data[key] !== null ? data[key] : undefined
+  }
+
+  return result as T
+}