Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support serializing/deserializing empty arrays #1850

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions apps/webapp/app/utils/taskEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
isExceptionSpanEvent,
millisecondsToNanoseconds,
NULL_SENTINEL,
EMPTY_ARRAY_SENTINEL,
SemanticInternalAttributes,
SpanEvent,
SpanEvents,
Expand Down Expand Up @@ -446,6 +447,10 @@ export function rehydrateJson(json: Prisma.JsonValue): any {
return null;
}

if (json === EMPTY_ARRAY_SENTINEL) {
return [];
}

if (typeof json === "string") {
return json;
}
Expand Down
5 changes: 5 additions & 0 deletions apps/webapp/app/v3/eventRepository.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
ExceptionEventProperties,
ExceptionSpanEvent,
NULL_SENTINEL,
EMPTY_ARRAY_SENTINEL,
PRIMARY_VARIANT,
SemanticInternalAttributes,
SpanEvent,
Expand Down Expand Up @@ -1593,6 +1594,10 @@ function rehydrateJson(json: Prisma.JsonValue): any {
return null;
}

if (json === EMPTY_ARRAY_SENTINEL) {
return [];
}

if (typeof json === "string") {
return json;
}
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/v3/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export {
primitiveValueOrflattenedAttributes,
unflattenAttributes,
NULL_SENTINEL,
EMPTY_ARRAY_SENTINEL,
} from "./utils/flattenAttributes.js";
export { omit } from "./utils/omit.js";
export {
Expand Down
21 changes: 18 additions & 3 deletions packages/core/src/v3/utils/flattenAttributes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Attributes } from "@opentelemetry/api";
import { debug } from "node:util";

export const NULL_SENTINEL = "$@null((";
export const EMPTY_ARRAY_SENTINEL = "$@empty_array((";
export const CIRCULAR_REFERENCE_SENTINEL = "$@circular((";

export function flattenAttributes(
Expand All @@ -20,6 +22,11 @@ export function flattenAttributes(
return result;
}

if (Array.isArray(obj) && obj.length === 0) {
result[prefix || ""] = EMPTY_ARRAY_SENTINEL;
return result;
}

if (typeof obj === "string") {
result[prefix || ""] = obj;
return result;
Expand Down Expand Up @@ -66,6 +73,10 @@ export function flattenAttributes(
}
}
}

if (!value.length) {
result[newPrefix] = EMPTY_ARRAY_SENTINEL;
}
} else if (isRecord(value)) {
// update null check here
Object.assign(result, flattenAttributes(value, newPrefix, seen));
Expand Down Expand Up @@ -98,7 +109,7 @@ export function unflattenAttributes(
Object.keys(obj).length === 1 &&
Object.keys(obj)[0] === ""
) {
return rehydrateNull(obj[""]) as any;
return rehydrateEmptyValues(obj[""]) as any;
}

if (Object.keys(obj).length === 0) {
Expand Down Expand Up @@ -150,7 +161,7 @@ export function unflattenAttributes(
const lastPart = parts[parts.length - 1];

if (lastPart !== undefined) {
current[lastPart] = rehydrateNull(rehydrateCircular(value));
current[lastPart] = rehydrateEmptyValues(rehydrateCircular(value));
}
}

Expand Down Expand Up @@ -201,10 +212,14 @@ export function primitiveValueOrflattenedAttributes(
return attributes;
}

function rehydrateNull(value: any): any {
function rehydrateEmptyValues(value: any): any {
if (value === NULL_SENTINEL) {
return null;
}

if (value === EMPTY_ARRAY_SENTINEL) {
return [];
}

return value;
}
40 changes: 35 additions & 5 deletions packages/core/test/flattenAttributes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,22 @@ describe("flattenAttributes", () => {
expect(unflattenAttributes(result)).toEqual(input);
});

it("flattens empty array attributes correctly", () => {
const input: number[] = [];

const result = flattenAttributes(input);
expect(result).toEqual({ "": "$@empty_array((" });
expect(unflattenAttributes(result)).toEqual(input);
});

it("flattens empty array child attributes correctly", () => {
const input: number[] = [];

const result = flattenAttributes({ input });
expect(result).toEqual({ input: "$@empty_array((" });
expect(unflattenAttributes(result)).toEqual({ input });
});

it("flattens complex objects correctly", () => {
const obj = {
level1: {
Expand Down Expand Up @@ -157,13 +173,13 @@ describe("flattenAttributes", () => {
expect(flattenAttributes(obj, "retry.byStatus")).toEqual(expected);
});

it("handles circular references correctly", () => {
it("handles circular references correctly", () => {
const user = { name: "Alice" };
user["blogPosts"] = [{ title: "Post 1", author: user }]; // Circular reference

const result = flattenAttributes(user);
expect(result).toEqual({
"name": "Alice",
name: "Alice",
"blogPosts.[0].title": "Post 1",
"blogPosts.[0].author": "$@circular((",
});
Expand All @@ -175,7 +191,7 @@ describe("flattenAttributes", () => {

const result = flattenAttributes(user);
expect(result).toEqual({
"name": "Bob",
name: "Bob",
"friends.[0]": "$@circular((",
});
});
Expand Down Expand Up @@ -246,10 +262,24 @@ describe("unflattenAttributes", () => {
};
expect(unflattenAttributes(flattened)).toEqual(expected);
});


it("correctly reconstructs empty arrays", () => {
const flattened = {
"": "$@empty_array((",
array1: "$@empty_array((",
"array2.[0]": "$@empty_array((",
};
const expected = {
"": [],
array1: [],
array2: [[]],
};
expect(unflattenAttributes(flattened)).toEqual(expected);
});

it("rehydrates circular references correctly", () => {
const flattened = {
"name": "Alice",
name: "Alice",
"blogPosts.[0].title": "Post 1",
"blogPosts.[0].author": "$@circular((",
};
Expand Down