Compare commits

...

1 Commits

Author SHA1 Message Date
Matt Aitken 96f042ccce Unflattening array fix for very large arrays (#1432)
🚀 Publish Trigger.dev Docker / units (push) Failing after 13m25s
🚀 Publish Trigger.dev Docker / typecheck (push) Failing after 13m25s
🚀 Publish Trigger.dev Docker / publish-webapp (push) Has been skipped
🚀 Publish Trigger.dev Docker / publish-worker (push) Has been skipped
* fix unflattening of array indices

* Get tests passing

---------

Co-authored-by: nicktrn <55853254+nicktrn@users.noreply.github.com>
Co-authored-by: Eric Allam <eallam@icloud.com>
# Conflicts:
#	.github/workflows/unit-tests.yml
2024-10-23 20:59:39 +01:00
2 changed files with 42 additions and 17 deletions
+28 -17
View File
@@ -95,36 +95,47 @@ export function unflattenAttributes(
const result: Record<string, unknown> = {};
for (const [key, value] of Object.entries(obj)) {
const parts = key.split(".").reduce((acc, part) => {
if (part.includes("[")) {
// Handling nested array indices
const subparts = part.split(/\[|\]/).filter((p) => p !== "");
acc.push(...subparts);
} else {
acc.push(part);
}
return acc;
}, [] as string[]);
const parts = key.split(".").reduce(
(acc, part) => {
if (part.startsWith("[") && part.endsWith("]")) {
// Handle array indices more precisely
const match = part.match(/^\[(\d+)\]$/);
if (match && match[1]) {
acc.push(parseInt(match[1]));
} else {
// Remove brackets for non-numeric array keys
acc.push(part.slice(1, -1));
}
} else {
acc.push(part);
}
return acc;
},
[] as (string | number)[]
);
let current: any = result;
for (let i = 0; i < parts.length - 1; i++) {
const part = parts[i];
const nextPart = parts[i + 1];
if (!part) {
if (!part && part !== 0) {
continue;
}
const nextPart = parts[i + 1];
const isArray = nextPart && /^\d+$/.test(nextPart);
if (isArray && !Array.isArray(current[part])) {
current[part] = [];
} else if (!isArray && current[part] === undefined) {
if (typeof nextPart === "number") {
// Ensure we create an array for numeric indices
current[part] = Array.isArray(current[part]) ? current[part] : [];
} else if (current[part] === undefined) {
// Create an object for non-numeric paths
current[part] = {};
}
current = current[part];
}
const lastPart = parts[parts.length - 1];
if (lastPart) {
if (lastPart !== undefined) {
current[lastPart] = rehydrateNull(value);
}
}
@@ -1,6 +1,20 @@
import { flattenAttributes, unflattenAttributes } from "../src/v3/utils/flattenAttributes.js";
describe("flattenAttributes", () => {
it("handles number keys correctl", () => {
expect(flattenAttributes({ bar: { "25": "foo" } })).toEqual({ "bar.25": "foo" });
expect(unflattenAttributes({ "bar.25": "foo" })).toEqual({ bar: { "25": "foo" } });
expect(flattenAttributes({ bar: ["foo", "baz"] })).toEqual({
"bar.[0]": "foo",
"bar.[1]": "baz",
});
expect(unflattenAttributes({ "bar.[0]": "foo", "bar.[1]": "baz" })).toEqual({
bar: ["foo", "baz"],
});
expect(flattenAttributes({ bar: { 25: "foo" } })).toEqual({ "bar.25": "foo" });
expect(unflattenAttributes({ "bar.25": "foo" })).toEqual({ bar: { 25: "foo" } });
});
it("handles null correctly", () => {
expect(flattenAttributes(null)).toEqual({ "": "$@null((" });
expect(unflattenAttributes({ "": "$@null((" })).toEqual(null);