Skip to content

Update to serialize unsaved instances using local ID's #2447

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

Merged
Show file tree
Hide file tree
Changes from 3 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
119 changes: 81 additions & 38 deletions packages/base/card-api.gts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
type Meta,
type CardFields,
type Relationship,
type ResourceID,
type LooseCardResource,
type LooseSingleCardDocument,
type CardDocument,
Expand Down Expand Up @@ -292,8 +293,10 @@ type JSONAPIResource =
};

export interface JSONAPISingleResourceDocument {
data: Partial<JSONAPIResource> & { id?: string; type: string };
included?: (Partial<JSONAPIResource> & { id: string; type: string })[];
data: Partial<JSONAPIResource> & { type: string } & { id?: string } & {
lid?: string;
};
included?: (Partial<JSONAPIResource> & ResourceID)[];
}

export interface Field<
Expand Down Expand Up @@ -894,35 +897,45 @@ class LinksTo<CardT extends CardDefConstructor> implements Field<CardT> {
},
};
}
// TODO add support for visited without an id
visited.add(value.id);
if (visited.has(value[localId])) {
return {
relationships: {
[this.name]: {
data: { type: 'card', lid: value[localId] },
},
},
};
}

visited.add(value.id ?? value[localId]);

let serialized = callSerializeHook(this.card, value, doc, visited, opts) as
| (JSONAPIResource & { id: string; type: string })
| null;
if (serialized) {
// TODO this goes away
if (!value[isSavedInstance]) {
throw new Error(
`the linksTo field '${this.name}' cannot be serialized with an unsaved card`,
);
}
let resource: JSONAPIResource = {
relationships: {
[this.name]: {
// TODO add support for unsaved card
links: {
self: makeRelativeURL(value.id, opts),
},
// we also write out the data form of the relationship
// which correlates to the included resource
data: { type: 'card', id: value.id },
...(value[isSavedInstance]
? {
links: {
self: makeRelativeURL(value.id, opts),
},
data: { type: 'card', id: value.id },
}
: {
data: { type: 'card', lid: value[localId] },
}),
},
},
};
if (
!(doc.included ?? []).find((r) => r.id === value.id) &&
doc.data.id !== value.id
(!(doc.included ?? []).find((r) => 'id' in r && r.id === value.id) &&
doc.data.id !== value.id) ||
(!(doc.included ?? []).find(
(r) => 'lid' in r && r.lid === value[localId],
) &&
doc.data.lid !== value[localId])
) {
doc.included = doc.included ?? [];
doc.included.push(serialized);
Expand Down Expand Up @@ -1076,6 +1089,12 @@ class LinksTo<CardT extends CardDefConstructor> implements Field<CardT> {
);
}

if (!json.data.id) {
throw new Error(
`should never get here: the document from the card we just fetched, ${reference}, did not have an id`,
);
}

let fieldInstance = (await createFromSerialized(
json.data,
json,
Expand Down Expand Up @@ -1252,32 +1271,47 @@ class LinksToMany<FieldT extends CardDefConstructor>
};
return;
}
// TODO add support for when value is unsaved and has no id
visited.add(value.id);
let serialized: JSONAPIResource & { id: string; type: string } =
callSerializeHook(this.card, value, doc, visited, opts);
if (!value[isSavedInstance]) {
// TODO this goes away
throw new Error(
`the linksToMany field '${this.name}' cannot be serialized with an unsaved card`,
);
if (visited.has(value[localId])) {
relationships[`${this.name}\.${i}`] = {
data: { type: 'card', lid: value[localId] },
};
return;
}

visited.add(value.id ?? value[localId]);
let serialized: JSONAPIResource & ResourceID = callSerializeHook(
this.card,
value,
doc,
visited,
opts,
);
if (serialized.meta && Object.keys(serialized.meta).length === 0) {
delete serialized.meta;
}
if (
!(doc.included ?? []).find((r) => r.id === value.id) &&
doc.data.id !== value.id
(!(doc.included ?? []).find((r) => 'id' in r && r.id === value.id) &&
doc.data.id !== value.id) ||
(!(doc.included ?? []).find(
(r) => 'lid' in r && r.lid === value[localId],
) &&
doc.data.lid !== value[localId])
) {
doc.included = doc.included ?? [];
doc.included.push(serialized);
}
// TODO add support for unsaved card

relationships[`${this.name}\.${i}`] = {
links: {
self: makeRelativeURL(value.id, opts),
},
data: { type: 'card', id: value.id },
...(value[isSavedInstance]
? {
links: {
self: makeRelativeURL(value.id, opts),
},
data: { type: 'card', id: value.id },
}
: {
data: { type: 'card', lid: value[localId] },
}),
};
});

Expand Down Expand Up @@ -1309,7 +1343,8 @@ class LinksToMany<FieldT extends CardDefConstructor>
)}`,
);
}
if (value.links.self == null) {
// TODO support lid (e,g, value.links will not exist in this case)
if (value.links?.self == null) {
return null;
}
let cachedInstance = identityContext.get(
Expand Down Expand Up @@ -1512,6 +1547,11 @@ class LinksToMany<FieldT extends CardDefConstructor>
)}`,
);
}
if (!json.data.id) {
throw new Error(
`should never get here: the document from the card we just fetched, ${reference}, did not have an id`,
);
}
let fieldInstance = (await createFromSerialized(
json.data,
json,
Expand Down Expand Up @@ -2357,7 +2397,7 @@ function serializeCardResource(
type: 'card',
meta: { adoptsFrom },
},
model.id ? { id: model.id } : undefined,
model.id ? { id: model.id } : { lid: model[localId] },
);
}

Expand All @@ -2366,7 +2406,10 @@ export function serializeCard(
opts?: SerializeOpts,
): LooseSingleCardDocument {
let doc = {
data: { type: 'card', ...(model.id != null ? { id: model.id } : {}) },
data: {
type: 'card',
...(model.id != null ? { id: model.id } : { lid: model[localId] }),
},
};
let modelRelativeTo = model[relativeTo];
let data = serializeCardResource(model, doc, {
Expand Down
Loading
Loading