Skip to content
Merged
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
33 changes: 33 additions & 0 deletions packages/optimizely-cms-sdk/src/graph/__test__/createQuery.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -553,3 +553,36 @@ describe('createFragment() empty objects', () => {
`);
});
});

describe('createFragment() with component properties', () => {
test('simple case', async () => {
const ctBlock = contentType({
key: 'ctBlock',
baseType: '_component',
properties: {
p1: { type: 'string' },
},
});
const ct1 = contentType({
key: 'ct1',
baseType: '_page',
properties: {
p1: { type: 'component', contentType: ctBlock },
},
});
initContentTypeRegistry([ct1, ctBlock]);
const result = await createFragment('ct1');
expect(result).toMatchInlineSnapshot(`
[
"fragment MediaMetadata on MediaMetadata { mimeType thumbnail content }",
"fragment ItemMetadata on ItemMetadata { changeset displayOption }",
"fragment InstanceMetadata on InstanceMetadata { changeset locales expired container owner routeSegment lastModifiedBy path createdBy }",
"fragment ContentUrl on ContentUrl { type default hierarchical internal graph base }",
"fragment IContentMetadata on IContentMetadata { key locale fallbackForLocale version displayName url {...ContentUrl} types published status created lastModified sortOrder variation ...MediaMetadata ...ItemMetadata ...InstanceMetadata }",
"fragment _IContent on _IContent { _id _metadata {...IContentMetadata} }",
"fragment ctBlockProperty on ctBlockProperty { __typename ctBlockProperty__p1:p1 }",
"fragment ct1 on ct1 { __typename ct1__p1:p1 { ...ctBlockProperty } ..._IContent }",
]
`);
});
});
78 changes: 78 additions & 0 deletions packages/optimizely-cms-sdk/src/graph/__test__/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { describe, expect, test } from 'vitest';
import { removeTypePrefix } from '../index.js';

describe('removeTypePrefix()', () => {
test('basic functionality', () => {
const input = {
__typename: 'T',
T__p1: 'p1',
T__p2: 42,
T__p3: ['p3', 32],
T__p4: { nested: 'p4' },
T__p5: { nested: ['p5'] },
ShouldBeKept__p6: 'p6',
};
const expected = {
__typename: 'T',
p1: 'p1',
p2: 42,
p3: ['p3', 32],
p4: { nested: 'p4' },
p5: { nested: ['p5'] },
ShouldBeKept__p6: 'p6',
};
expect(removeTypePrefix(input)).toStrictEqual(expected);
});

test('should remove prefixes only in the same level', () => {
const input = {
__typename: 'T',
T__p1: { T_shouldBeKept: 'shouldBeKept' },
};
const expected = {
__typename: 'T',
p1: { T_shouldBeKept: 'shouldBeKept' },
};
expect(removeTypePrefix(input)).toStrictEqual(expected);
});

test('should work for nested objects', () => {
const input = {
__typename: 'T',
T__p1: {
__typename: 'U',
U__p1: 'p1',
U__p2: {
__typename: 'V',
V__p1: 'p1',
},
},
T__p2: [{ __typename: 'U', U__p1: 'p1' }],
};
const expected = {
__typename: 'T',
p1: {
__typename: 'U',
p1: 'p1',
p2: {
__typename: 'V',
p1: 'p1',
},
},
p2: [{ __typename: 'U', p1: 'p1' }],
};
expect(removeTypePrefix(input)).toStrictEqual(expected);
});

test('should not do anything if __typename is not found', () => {
const input = {
T__p1: 'hello',
T__p2: 42,
T__p3: ['hello', 32],
T__p4: { nested: 'nested' },
T__p5: { nested: ['hello'] },
};

expect(removeTypePrefix(input)).toStrictEqual(input);
});
});
15 changes: 12 additions & 3 deletions packages/optimizely-cms-sdk/src/graph/createQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,16 @@ function convertProperty(
name: string,
property: AnyProperty,
rootName: string,
suffix: string,
visited: Set<string>
): { fields: string[]; extraFragments: string[] } {
const result = convertPropertyField(name, property, rootName, visited);
const result = convertPropertyField(
name,
property,
rootName,
suffix,
visited
);

// logs warnings if the fragment generation causes potential issues
const warningMessage = checkTypeConstraintIssues(rootName, property, result);
Expand All @@ -95,12 +102,13 @@ function convertPropertyField(
name: string,
property: AnyProperty,
rootName: string,
suffix: string,
visited: Set<string>
): { fields: string[]; extraFragments: string[] } {
const fields: string[] = [];
const subfields: string[] = [];
const extraFragments: string[] = [];
const nameInFragment = `${rootName}__${name}:${name}`;
const nameInFragment = `${rootName}${suffix}__${name}:${name}`;

if (property.type === 'component') {
const key = property.contentType.key;
Expand Down Expand Up @@ -146,7 +154,7 @@ function convertPropertyField(
extraFragments.push(CONTENT_URL_FRAGMENT);
fields.push(`${nameInFragment} { key url { ...ContentUrl }}`);
} else if (property.type === 'array') {
const f = convertProperty(name, property.items, rootName, visited);
const f = convertProperty(name, property.items, rootName, suffix, visited);
fields.push(...f.fields);
extraFragments.push(...f.extraFragments);
} else {
Expand Down Expand Up @@ -237,6 +245,7 @@ export function createFragment(
propKey,
prop,
contentTypeName,
suffix,
visited
);
fields.push(...f);
Expand Down
5 changes: 4 additions & 1 deletion packages/optimizely-cms-sdk/src/graph/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,11 @@ type GetLinksResponse = {
*
* @param obj - The object to process (typically a GraphQL response)
* @returns A new object with prefixes removed, or the original value for primitives
*
* Note: this function is exported only on this level for testing purposes.
* It should not be exported in the user-facing API
*/
function removeTypePrefix(obj: any): any {
export function removeTypePrefix(obj: any): any {
if (Array.isArray(obj)) {
return obj.map((e) => removeTypePrefix(e));
}
Expand Down
Loading