Skip to content

Commit

Permalink
fix: make serialize utils smarter (#9692)
Browse files Browse the repository at this point in the history
* fix: make serialize utils smarter

* fix lint
  • Loading branch information
runspired authored Feb 22, 2025
1 parent 2470660 commit 8818a7c
Showing 1 changed file with 54 additions and 11 deletions.
65 changes: 54 additions & 11 deletions packages/json-api/src/-private/serialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@ import type { StableRecordIdentifier } from '@warp-drive/core-types';
import type { Cache } from '@warp-drive/core-types/cache';
import type { Relationship } from '@warp-drive/core-types/cache/relationship';
import type { Value } from '@warp-drive/core-types/json/raw';
import type { ResourceObject } from '@warp-drive/core-types/spec/json-api-raw';
import type { InnerRelationshipDocument, ResourceObject } from '@warp-drive/core-types/spec/json-api-raw';

type ChangedRelationshipData = {
data: Relationship['data'];
};
type ChangedRelationshipData = InnerRelationshipDocument;

export type JsonApiResourcePatch = {
type: string;
Expand Down Expand Up @@ -44,16 +42,62 @@ export function serializeResources(
};
}

type SerializedRef =
| {
id: string;
type: string;
}
| { id: null; lid: string; type: string };

function fixRef({
id,
lid,
type,
}: { id: string; lid?: string; type: string } | { id: null; lid: string; type: string }): SerializedRef {
if (id !== null) {
return { id, type };
}
return { id, lid, type };
}

function fixRelData(
rel: Relationship['data'] | InnerRelationshipDocument['data']
): SerializedRef | SerializedRef[] | null {
if (Array.isArray(rel)) {
return rel.map((ref) => fixRef(ref));
} else if (typeof rel === 'object' && rel !== null) {
return fixRef(rel);
}
return null;
}

function _serializeResource(cache: Cache, identifier: StableRecordIdentifier): ResourceObject {
const { id, lid, type } = identifier;
// yup! this method actually does nothing. It's just here for the dev assertion
// and to assist in providing a little sugar to the consuming app via the `serializeResources` utility
const record = cache.peek(identifier) as ResourceObject;
// peek gives us everything we want, but since its referentially the same data
// as is in the cache we clone it to avoid any accidental mutations
const record = structuredClone(cache.peek(identifier)) as ResourceObject;
assert(
`A record with id ${String(id)} and type ${type} for lid ${lid} was not found not in the supplied Cache.`,
record
);

// remove lid from anything that has an ID and slice any relationship arrays
if (record.id !== null) {
delete record.lid;
}

if (record.relationships) {
for (const key of Object.keys(record.relationships)) {
const relationship = record.relationships[key];
relationship.data = fixRelData(relationship.data);
if (Array.isArray(relationship.data)) {
relationship.data = relationship.data.map((ref) => fixRef(ref));
} else if (typeof relationship.data === 'object' && relationship.data !== null) {
relationship.data = fixRef(relationship.data);
}
}
}

return record;
}

Expand Down Expand Up @@ -87,10 +131,9 @@ export function serializePatch(
// options: { include?: string[] } = {}
): { data: JsonApiResourcePatch } {
const { id, lid, type } = identifier;
const record = cache.peek(identifier) as ResourceObject;
assert(
`A record with id ${String(id)} and type ${type} for lid ${lid} was not found not in the supplied Cache.`,
record
cache.peek(identifier)
);

const data: JsonApiResourcePatch = {
Expand All @@ -106,7 +149,7 @@ export function serializePatch(
Object.keys(attrsChanges).forEach((key) => {
const change = attrsChanges[key];
const newVal = change[1];
attributes[key] = newVal === undefined ? null : newVal;
attributes[key] = newVal === undefined ? null : structuredClone(newVal);
});

data.attributes = attributes;
Expand All @@ -116,7 +159,7 @@ export function serializePatch(
if (changedRelationships.size) {
const relationships: Record<string, ChangedRelationshipData> = {};
changedRelationships.forEach((diff, key) => {
relationships[key] = { data: diff.localState };
relationships[key] = { data: fixRelData(diff.localState) } as ChangedRelationshipData;
});

data.relationships = relationships;
Expand Down

0 comments on commit 8818a7c

Please sign in to comment.