Skip to main content
Glama
Arize-ai

@arizeai/phoenix-mcp

Official
by Arize-ai
objectMappingUtils.test.ts10.9 kB
import { ObjectMapping } from "../../src/types/data"; import { remapObject } from "../../src/utils/objectMappingUtils"; import { describe, expect, it } from "vitest"; describe("objectMappingUtils", () => { describe("remapObject", () => { const testData = { id: 123, name: "John Doe", age: 30, email: "john@example.com", address: { street: "123 Main St", city: "New York", zipCode: "10001", country: "USA", }, hobbies: ["reading", "swimming", "coding"], scores: [85, 92, 78, 96], metadata: { created: "2023-01-01", tags: ["user", "premium"], settings: { theme: "dark", notifications: true, language: "en", }, }, isActive: true, lastLogin: "2023-12-01", }; describe("data preservation with mapping", () => { it("should preserve original data and add mapped fields", () => { const mapping: ObjectMapping<typeof testData> = { userName: "name", userAge: "age", }; const result = remapObject(testData, mapping); // Result should contain all original fields plus the mapped fields expect(result).toEqual({ ...testData, // All original fields preserved userName: "John Doe", // Added mapped field userAge: 30, // Added mapped field }); }); it("should handle empty mapping by returning original data", () => { const mapping: ObjectMapping<typeof testData> = {}; const result = remapObject(testData, mapping); // Should return exact copy of original data expect(result).toEqual(testData); }); it("should overwrite existing fields when mapping to same key", () => { const mapping: ObjectMapping<typeof testData> = { name: "email", // Overwrite name with email value newField: "age", // Add new field }; const result = remapObject(testData, mapping); expect(result).toEqual({ ...testData, name: "john@example.com", // Overwritten newField: 30, // Added }); }); }); describe("dot notation extraction", () => { it("should extract simple properties using dot notation", () => { const mapping: ObjectMapping<typeof testData> = { extractedName: "name", extractedEmail: "email", extractedActive: "isActive", }; const result = remapObject(testData, mapping); expect(result).toEqual({ ...testData, extractedName: "John Doe", extractedEmail: "john@example.com", extractedActive: true, }); }); it("should extract nested properties using dot notation", () => { const mapping: ObjectMapping<typeof testData> = { extractedStreet: "address.street", extractedCity: "address.city", extractedTheme: "metadata.settings.theme", }; const result = remapObject(testData, mapping); expect(result).toEqual({ ...testData, extractedStreet: "123 Main St", extractedCity: "New York", extractedTheme: "dark", }); }); it("should extract array elements using dot notation", () => { const mapping: ObjectMapping<typeof testData> = { firstHobby: "hobbies[0]", lastHobby: "hobbies[2]", secondScore: "scores[1]", firstTag: "metadata.tags[0]", }; const result = remapObject(testData, mapping); expect(result).toEqual({ ...testData, firstHobby: "reading", lastHobby: "coding", secondScore: 92, firstTag: "user", }); }); it("should extract entire arrays using dot notation", () => { const mapping: ObjectMapping<typeof testData> = { allHobbies: "hobbies", allScores: "scores", allTags: "metadata.tags", }; const result = remapObject(testData, mapping); expect(result).toEqual({ ...testData, allHobbies: ["reading", "swimming", "coding"], allScores: [85, 92, 78, 96], allTags: ["user", "premium"], }); }); }); describe("function-based mapping", () => { it("should support function-based transformations", () => { const mapping: ObjectMapping<typeof testData> = { upperCaseName: (data) => data.name.toUpperCase(), hobbyCount: (data) => data.hobbies.length, isAdult: (data) => data.age >= 18, }; const result = remapObject(testData, mapping); expect(result).toEqual({ ...testData, upperCaseName: "JOHN DOE", hobbyCount: 3, isAdult: true, }); }); it("should handle complex function transformations", () => { const mapping: ObjectMapping<typeof testData> = { fullInfo: (data) => `${data.name} (${data.age})`, averageScore: (data) => data.scores.reduce((a, b) => a + b, 0) / data.scores.length, addressSummary: (data) => `${data.address.city}, ${data.address.country}`, }; const result = remapObject(testData, mapping); expect(result).toEqual({ ...testData, fullInfo: "John Doe (30)", averageScore: 87.75, addressSummary: "New York, USA", }); }); }); describe("mixed mapping types", () => { it("should handle mixed dot notation and function mappings", () => { const mapping: ObjectMapping<typeof testData> = { // Dot notation extractions extractedName: "name", extractedStreet: "address.street", firstHobby: "hobbies[0]", // Function-based transformations upperCaseName: (data) => data.name.toUpperCase(), isAdult: (data) => data.age >= 18, }; const result = remapObject(testData, mapping); expect(result).toEqual({ ...testData, extractedName: "John Doe", extractedStreet: "123 Main St", firstHobby: "reading", upperCaseName: "JOHN DOE", isAdult: true, }); }); }); describe("edge cases", () => { it("should handle non-existent paths gracefully", () => { const mapping: ObjectMapping<typeof testData> = { nonExistent: "nonExistent", deepNonExistent: "address.nonExistent.deep", arrayOutOfBounds: "hobbies[10]", }; const result = remapObject(testData, mapping); expect(result).toEqual({ ...testData, nonExistent: undefined, deepNonExistent: undefined, arrayOutOfBounds: undefined, }); }); it("should handle empty data object", () => { const emptyData = {}; const mapping: ObjectMapping<typeof emptyData> = { anything: "anything", somethingElse: (data) => data, }; const result = remapObject(emptyData, mapping); expect(result).toEqual({ anything: undefined, somethingElse: {}, }); }); it("should handle null and undefined values in data", () => { const dataWithNulls = { name: "John", nullValue: null, undefinedValue: undefined, nested: { value: "test", nullNested: null, }, }; const mapping: ObjectMapping<typeof dataWithNulls> = { extractedName: "name", extractedNull: "nullValue", extractedUndef: "undefinedValue", extractedNestedNull: "nested.nullNested", }; const result = remapObject(dataWithNulls, mapping); expect(result).toEqual({ ...dataWithNulls, extractedName: "John", extractedNull: null, extractedUndef: undefined, extractedNestedNull: null, }); }); }); describe("real-world scenarios", () => { it("should handle API response enrichment", () => { const apiResponse = { user_id: 123, user_name: "john_doe", user_profile: { first_name: "John", last_name: "Doe", contact_info: { email: "john@example.com", phone: "+1234567890", }, }, preferences: { theme: "dark", notifications: ["email", "push"], }, last_activity: "2023-12-01T10:30:00Z", }; // Add computed fields while preserving original structure const mapping: ObjectMapping<typeof apiResponse> = { // Extract and rename some fields id: "user_id", username: "user_name", email: "user_profile.contact_info.email", // Add computed fields fullName: (data) => `${data.user_profile.first_name} ${data.user_profile.last_name}`, displayName: (data) => data.user_profile.first_name, hasNotifications: (data) => data.preferences.notifications.length > 0, }; const result = remapObject(apiResponse, mapping); expect(result).toEqual({ ...apiResponse, // All original fields preserved // Plus new computed/extracted fields id: 123, username: "john_doe", email: "john@example.com", fullName: "John Doe", displayName: "John", hasNotifications: true, }); }); it("should handle data transformation with field overrides", () => { const rawData = { status: "active", count: "42", // String that should be converted to number tags: "user,premium", // String that should be split to array metadata: { created: "2023-01-01", score: 85.5, }, }; const mapping: ObjectMapping<typeof rawData> = { // Override existing fields with transformed values count: (data) => parseInt(data.count, 10), tags: (data) => data.tags.split(","), // Add new computed fields isActive: (data) => data.status === "active", scoreGrade: (data) => data.metadata.score >= 90 ? "A" : data.metadata.score >= 80 ? "B" : "C", }; const result = remapObject(rawData, mapping); expect(result).toEqual({ ...rawData, count: 42, // Overridden with number tags: ["user", "premium"], // Overridden with array isActive: true, // New field scoreGrade: "B", // New field }); }); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Arize-ai/phoenix'

If you have feedback or need assistance with the MCP directory API, please join our Discord server