FIX: Hydration of embedded records (#22809)

The store expects values for property names ending with `_id` to be a resource id
and `_ids` to be an array of resource ids.

This change ensures the store gracefully handles situations where an
embedded field with incompliant data structure sneaks its way to production.
This commit is contained in:
Selase Krakani 2023-07-28 15:58:55 +00:00 committed by GitHub
parent a8c504aee4
commit 4471eabd49
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 29 additions and 1 deletions

View File

@ -6,6 +6,7 @@ import ResultSet from "discourse/models/result-set";
import { ajax } from "discourse/lib/ajax";
import { getRegister } from "discourse-common/lib/get-owner";
import { underscore } from "@ember/string";
import { warn } from "@ember/debug";
let _identityMap;
@ -325,9 +326,18 @@ export default Service.extend({
const subType = m[1];
if (m[2]) {
if (!Array.isArray(obj[k])) {
warn(`Expected an array of resource ids for ${type}.${k}`, {
id: "discourse.store.hydrate-embedded",
});
return;
}
const hydrated = obj[k].map((id) =>
this._lookupSubType(subType, type, id, root)
);
obj[this.pluralize(subType)] = hydrated || [];
delete obj[k];
} else {

View File

@ -12,7 +12,14 @@ const fruits = [
{ id: 1, name: "apple", farmer_id: 1, color_ids: [1, 2], category_id: 4 },
{ id: 2, name: "banana", farmer_id: 1, color_ids: [3], category_id: 3 },
{ id: 3, name: "grape", farmer_id: 2, color_ids: [2], category_id: 5 },
{ id: 4, name: "orange", farmer_id: null, color_ids: [2], category_id: 5 },
{
id: 4,
name: "orange",
farmer_id: null,
color_ids: [2],
category_id: 5,
other_fruit_ids: { apple: 1, banana: 2 },
},
];
const farmers = [

View File

@ -263,4 +263,15 @@ module("Unit | Service | store", function (hooks) {
assert.true(Array.isArray(result.topics));
assert.strictEqual(result.filter, "topics/created-by/trout");
});
test("Spec incompliant embedded record name", async function (assert) {
const store = getOwner(this).lookup("service:store");
const fruit = await store.find("fruit", 4);
assert.propContains(
fruit.other_fruit_ids,
{ apple: 1, banana: 2 },
"embedded record remains unhydrated"
);
});
});