Skip to content
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

fix: serializeResourceLinkage returns the candidate if already a linkage #4

Merged
merged 1 commit into from
Dec 7, 2024
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
13 changes: 13 additions & 0 deletions __tests__/serializers/serializeResourceLinkage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,19 @@ describe('`serializeResourceLinkage`', () => {
chance = new Chance();
});

describe('when given a resource linkage', () => {
it('should return the resource linkage as is', () => {
const resourceLinkage = {
type: chance.string(),
id: chance.string(),
};

expect(serializeResourceLinkage(resourceLinkage)).toEqual(
resourceLinkage,
);
});
});

describe('when given an array of class instances', () => {
it('should throw an error if some element in the array is not an object', () => {
const classInstances = [1];
Expand Down
80 changes: 80 additions & 0 deletions __tests__/serializers/utils/isResourceIdentifierObject.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { isResourceIdentifierObject } from '../../../src/serializers/utils/isResourceIdentifierObject';

describe('`isResourceIdentifierObject`', () => {
it('it should return `false` if `resourceIdentifierObjectCandidate` is null', () => {
const resourceIdentifierObjectCandidate = null;

expect(isResourceIdentifierObject(resourceIdentifierObjectCandidate)).toBe(
false,
);
});

it('it should return `false` if `resourceIdentifierObjectCandidate` is not an object', () => {
const resourceIdentifierObjectCandidate = 'not an object';

expect(isResourceIdentifierObject(resourceIdentifierObjectCandidate)).toBe(
false,
);
});

it('it should return `false` if `resourceIdentifierObjectCandidate` is an array', () => {
const resourceIdentifierObjectCandidate: unknown[] = [];

expect(isResourceIdentifierObject(resourceIdentifierObjectCandidate)).toBe(
false,
);
});

it('it should return `false` if `resourceIdentifierObjectCandidate` does not have a `type` property', () => {
const resourceIdentifierObjectCandidate = {
id: '1',
};

expect(isResourceIdentifierObject(resourceIdentifierObjectCandidate)).toBe(
false,
);
});

it('it should return `false` if `resourceIdentifierObjectCandidate.type` is not a string', () => {
const resourceIdentifierObjectCandidate = {
type: 1,
id: '1',
};

expect(isResourceIdentifierObject(resourceIdentifierObjectCandidate)).toBe(
false,
);
});

it('it should return `false` if `resourceIdentifierObjectCandidate` does not have an `id` property', () => {
const resourceIdentifierObjectCandidate = {
type: 'test',
};

expect(isResourceIdentifierObject(resourceIdentifierObjectCandidate)).toBe(
false,
);
});

it('it should return `false` if `resourceIdentifierObjectCandidate.id` is not a string', () => {
const resourceIdentifierObjectCandidate = {
type: 'test',
id: 1,
};

expect(isResourceIdentifierObject(resourceIdentifierObjectCandidate)).toBe(
false,
);
});

it('it should return `true` if `resourceIdentifierObjectCandidate` is a valid JSON:API Resource Identifier Object', () => {
const resourceIdentifierObjectCandidate = {
type: 'test',
id: '1',
};

expect(isResourceIdentifierObject(resourceIdentifierObjectCandidate)).toBe(
true,
);
});
});
33 changes: 33 additions & 0 deletions __tests__/serializers/utils/isResourceLinkage.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { isResourceLinkage } from '../../../src/serializers/utils/isResourceLinkage';

import { isResourceIdentifierObject } from '../../../src/serializers/utils/isResourceIdentifierObject';

jest.mock('../../../src/serializers/utils/isResourceIdentifierObject');

const isResourceIdentifierObjectMocked = jest.mocked(
isResourceIdentifierObject,
);

describe('`isResourceLinkage`', () => {
it('should return true if `resourceLinkageCandidate` is `null`', () => {
const resourceLinkageCandidate = null;

expect(isResourceLinkage(resourceLinkageCandidate)).toBe(true);
});

it('should return true if `resourceLinkageCandidate` is an array of `JSONAPIResourceIdentifierObject`', () => {
isResourceIdentifierObjectMocked.mockReturnValue(true);

const resourceLinkageCandidate = ['foo', 'bar'];

expect(isResourceLinkage(resourceLinkageCandidate)).toBe(true);
});

it('should return true if `resourceLinkageCandidate` is a `JSONAPIResourceIdentifierObject`', () => {
isResourceIdentifierObjectMocked.mockReturnValue(true);

const resourceLinkageCandidate = 'foo';

expect(isResourceLinkage(resourceLinkageCandidate)).toBe(true);
});
});
9 changes: 7 additions & 2 deletions src/serializers/serializeResourceLinkage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@ import { resourceSymbol } from '../decorators/resource';
import { collect } from './utils/collect';
import { getMetadataBySymbol } from './utils/getMetadataBySymbol';
import { isObject } from './utils/isObject';
import { isResourceLinkage } from './utils/isResourceLinkage';

import type { JSONAPIResourceLinkage } from '../types/resourceLinkage';

export const serializeResourceLinkage = <I extends object>(
classInstance_s: I,
): Exclude<JSONAPIResourceLinkage, null> => {
classInstance_s: I | JSONAPIResourceLinkage,
): JSONAPIResourceLinkage => {
if (isResourceLinkage(classInstance_s)) {
return classInstance_s;
}

if (Array.isArray(classInstance_s)) {
if (!classInstance_s.every(isObject)) {
throw new Error(
Expand Down
34 changes: 34 additions & 0 deletions src/serializers/utils/isResourceIdentifierObject.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { JSONAPIResourceIdentifierObject } from '../../types/resourceIdentifierObject';

export const isResourceIdentifierObject = (
resourceIdentifierObjectCandidate: unknown,
): resourceIdentifierObjectCandidate is JSONAPIResourceIdentifierObject => {
if (resourceIdentifierObjectCandidate === null) {
return false;
}

if (
typeof resourceIdentifierObjectCandidate !== 'object' ||
Array.isArray(resourceIdentifierObjectCandidate)
) {
return false;
}

if ('type' in resourceIdentifierObjectCandidate === false) {
return false;
}

if (typeof resourceIdentifierObjectCandidate.type !== 'string') {
return false;
}

if ('id' in resourceIdentifierObjectCandidate === false) {
return false;
}

if (typeof resourceIdentifierObjectCandidate.id !== 'string') {
return false;
}

return true;
};
17 changes: 17 additions & 0 deletions src/serializers/utils/isResourceLinkage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { isResourceIdentifierObject } from './isResourceIdentifierObject';

import type { JSONAPIResourceLinkage } from '../../types/resourceLinkage';

export const isResourceLinkage = (
resourceLinkageCandidate: unknown,
): resourceLinkageCandidate is JSONAPIResourceLinkage => {
if (resourceLinkageCandidate === null) {
return true;
}

if (Array.isArray(resourceLinkageCandidate)) {
return resourceLinkageCandidate.every(isResourceIdentifierObject);
}

return isResourceIdentifierObject(resourceLinkageCandidate);
};
Loading