Skip to content

Commit 14eab70

Browse files
committed
implemented createItem, deleteItem and deleteItems methods
1 parent 38cf1cd commit 14eab70

File tree

15 files changed

+915
-514
lines changed

15 files changed

+915
-514
lines changed

package-lock.json

Lines changed: 591 additions & 489 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
},
3030
"homepage": "https://github.com/js-items/ky#readme",
3131
"devDependencies": {
32-
"@js-items/foundation": "1.0.24",
32+
"@js-items/foundation": "1.0.25",
3333
"@kube-js/semantic-release": "1.0.7",
3434
"@kube-js/tscommons": "1.0.5",
3535
"@types/jest": "24.0.13",

src/FacadeConfig.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export type Document = any;
77

88
export default interface FacadeConfig<I extends Item> {
99
readonly ky: () => Promise<typeof ky>;
10-
readonly createFilter: (filter: Filter<I>) => any;
10+
readonly createFilter: (filter?: Filter<I>) => any;
1111
readonly convertDocumentIntoItem: (document: Document) => I;
1212
readonly convertItemIntoOptions: ConvertItemIntoOptions<I>;
1313
readonly createSort: (sort: Sort<I>) => any;

src/FactoryConfig.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export default interface FactoryConfig<I extends Item> {
3131
readonly paginationKey?: string;
3232
readonly envelopParamName?: string;
3333
readonly prettyParamName?: string;
34-
readonly createFilter: (filter: Filter<I>) => any;
34+
readonly createFilter: (filter?: Filter<I>) => any;
3535
readonly convertDocumentIntoItem: (document: Document) => I;
3636
readonly convertItemIntoOptions: ConvertItemIntoOptions<I>;
3737
readonly createSort: (sort: Sort<I>) => any;

src/factory.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// TODO: uncomment all commented lines
33
import { /* DeleteItem, */ Item } from '@js-items/foundation';
44
// import Facade from '@js-items/foundation/dist/Facade';
5+
// import Facade from '@js-items/foundation/dist/Facade';
56
import _defaultTo from 'ramda/src/defaultTo';
67
import FacadeConfig from './FacadeConfig';
78
import FactoryConfig from './FactoryConfig';
@@ -14,6 +15,7 @@ import defaultCreateItem from './functions/createItem';
1415
// import defaultUpdateItem from './functions/updateItem';
1516
// import { Handler } from './types/handler';
1617
import defaultConvertItemToOptions from './utils/defaultConvertItemToOptions';
18+
import { emptyOptions } from './utils/emptyOptions';
1719

1820
export default <I extends Item>({
1921
deleteItem,
@@ -25,22 +27,21 @@ export default <I extends Item>({
2527
createItem,
2628
convertItemIntoOptions,
2729
...config
28-
}: // TODO: implement the missing method on @js-items/express and @js-items/ky
29-
FactoryConfig<
30+
}: FactoryConfig<
3031
I
31-
>): any /* TODO: removed any and uncomment when implemented: Omit<Facade<I> , 'countItems'>*/ => {
32+
>): any /* uncomment when finished entirely: Facade<I> */ => {
3233
const itemIntoOptions = _defaultTo(defaultConvertItemToOptions)(
3334
convertItemIntoOptions
3435
);
3536

3637
const facadeConfig: FacadeConfig<I> = {
3738
convertDocumentIntoItem: (document: any) => document,
3839
convertItemIntoOptions: itemIntoOptions,
39-
createFilter: (filter: any) => filter,
40+
createFilter: emptyOptions,
4041
createItemOptions: defaultConvertItemToOptions,
4142
createSort: (sort: any) => sort,
4243
defaultPaginationLimit: 10,
43-
deleteItemOptions: itemIntoOptions,
44+
deleteItemOptions: emptyOptions,
4445
deleteItemsOptions: itemIntoOptions,
4546
getItemOptions: itemIntoOptions,
4647
getItemsOptions: itemIntoOptions,
Lines changed: 76 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,79 @@
1+
// tslint:disable:no-any
2+
import { ConflictingItemError } from '@js-items/foundation';
3+
import testItem from '@js-items/foundation/dist/functions/utils/testItem';
4+
import { config } from '../../utils/testConfig';
5+
import createItem from './index';
6+
7+
beforeEach(() => jest.clearAllMocks());
8+
19
describe('@createItem', () => {
2-
it('tests', () => {
3-
// TODO: implements tests
4-
expect(true).toBe(true);
10+
it('creates item', async () => {
11+
const kyMock = jest.fn(() => ({
12+
json: () => Promise.resolve({ item: testItem }),
13+
}));
14+
15+
const createItemOptionsMock = jest.fn(() => ({}));
16+
17+
const { item } = await createItem({
18+
...config,
19+
createItemOptions: createItemOptionsMock,
20+
ky: () => Promise.resolve(kyMock) as any,
21+
})({
22+
id: testItem.id,
23+
item: testItem,
24+
});
25+
26+
expect(createItemOptionsMock).toBeCalledWith(testItem);
27+
28+
expect(config.convertDocumentIntoItem).toBeCalledWith(testItem);
29+
30+
expect(item).toEqual(testItem);
31+
32+
expect(kyMock).toBeCalledWith('', {
33+
json: { item: testItem },
34+
method: 'post',
35+
});
36+
});
37+
38+
it('creates item with custom json object', async () => {
39+
const kyMock = jest.fn(() => ({
40+
json: () => Promise.resolve({ item: testItem, otherProp: 'test' }),
41+
}));
42+
43+
const createItemOptionsMock = jest.fn(() => ({
44+
json: { otherProp: 'test' },
45+
}));
46+
47+
await createItem({
48+
...config,
49+
createItemOptions: createItemOptionsMock,
50+
ky: () => Promise.resolve(kyMock) as any,
51+
})({
52+
item: testItem,
53+
});
54+
55+
expect(kyMock).toBeCalledWith('', {
56+
json: { item: testItem, otherProp: 'test' },
57+
method: 'post',
58+
});
59+
});
60+
61+
it('does not create item', async () => {
62+
const error = new ConflictingItemError('TestItem');
63+
64+
const facadeConfig = {
65+
...config,
66+
createItemOptions: jest.fn(() => ({ json: { item: testItem } })),
67+
ky: jest.fn(() => Promise.reject(error)),
68+
};
69+
70+
try {
71+
await createItem(facadeConfig)({
72+
id: testItem.id,
73+
item: testItem,
74+
});
75+
} catch (e) {
76+
expect(e).toEqual(error);
77+
}
578
});
679
});

src/functions/createItem/index.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
// tslint:disable:no-any
2-
import { ConflictingItemError, CreateItem, Item } from '@js-items/foundation';
2+
import { CreateItem, Item } from '@js-items/foundation';
33
import { Result } from '@js-items/foundation/dist/functions/GetItem';
4-
import { CONFLICT } from 'http-status-codes';
54
import _isNil from 'ramda/src/isNil';
65
import FacadeConfig from '../../FacadeConfig';
76

87
export default <I extends Item>(
98
config: FacadeConfig<I>
10-
): CreateItem<I> => async ({ id, item }) => {
9+
): CreateItem<I> => async ({ item, id }) => {
1110
try {
1211
const connection = await config.ky();
1312

@@ -31,10 +30,6 @@ export default <I extends Item>(
3130
item: config.convertDocumentIntoItem(response.item),
3231
});
3332
} catch (error) {
34-
if (error.response.status === CONFLICT) {
35-
return Promise.reject(new ConflictingItemError(config.itemName, id));
36-
}
37-
3833
return Promise.reject(error);
3934
}
4035
};
Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,69 @@
1+
// tslint:disable:no-any
2+
import { ItemNotFoundError } from '@js-items/foundation';
3+
import testItem from '@js-items/foundation/dist/functions/utils/testItem';
4+
import { config } from '../../utils/testConfig';
5+
import deleteItem from './index';
6+
7+
beforeEach(() => jest.clearAllMocks());
8+
19
describe('@deleteItem', () => {
2-
it('tests', () => {
3-
// TODO: implements tests
4-
expect(true).toBe(true);
10+
it('deletes item with no filter', async () => {
11+
const kyMock = jest.fn();
12+
13+
await deleteItem({
14+
...config,
15+
ky: () => Promise.resolve(kyMock) as any,
16+
})({
17+
id: testItem.id,
18+
});
19+
20+
expect(config.createFilter).toBeCalledWith({});
21+
22+
expect(kyMock).toBeCalledWith(`/${testItem.id}`, {
23+
method: 'delete',
24+
searchParams: { filter: JSON.stringify({}) },
25+
});
26+
});
27+
28+
it('deletes item with filter and custom search params', async () => {
29+
const kyMock = jest.fn();
30+
const filter = {
31+
id: { $eq: testItem.id },
32+
};
33+
const createFilterMock = jest.fn(() => filter);
34+
35+
await deleteItem({
36+
...config,
37+
createFilter: createFilterMock,
38+
deleteItemOptions: () => ({ searchParams: { pretty: 'true' } }),
39+
ky: () => Promise.resolve(kyMock) as any,
40+
})({
41+
filter,
42+
id: testItem.id,
43+
});
44+
45+
expect(createFilterMock).toBeCalledWith(filter);
46+
47+
expect(kyMock).toBeCalledWith(`/${testItem.id}`, {
48+
method: 'delete',
49+
searchParams: { pretty: 'true', filter: JSON.stringify(filter) },
50+
});
51+
});
52+
53+
it('does not delete item', async () => {
54+
const error = new ItemNotFoundError('TestItem', testItem.id);
55+
56+
const facadeConfig = {
57+
...config,
58+
ky: jest.fn(() => Promise.reject(error)),
59+
};
60+
61+
try {
62+
await deleteItem(facadeConfig)({
63+
id: testItem.id,
64+
});
65+
} catch (e) {
66+
expect(e).toEqual(error);
67+
}
568
});
669
});

src/functions/deleteItem/index.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// tslint:disable:no-any
2+
import { DeleteItem, Item } from '@js-items/foundation';
3+
import _isNil from 'ramda/src/isNil';
4+
import FacadeConfig from '../../FacadeConfig';
5+
6+
export default <I extends Item>(
7+
config: FacadeConfig<I>
8+
): DeleteItem<I> => async ({ filter = {}, id }) => {
9+
try {
10+
const connection = await config.ky();
11+
12+
const options = config.deleteItemOptions();
13+
14+
const createdFilter = config.createFilter(filter);
15+
16+
const params = { filter: JSON.stringify(createdFilter) };
17+
18+
const searchParams =
19+
!_isNil(options) && !_isNil((options as any).searchParams)
20+
? (options as any).searchParams
21+
: {};
22+
23+
await connection(`/${id}`, {
24+
...options,
25+
method: 'delete',
26+
searchParams: { ...searchParams, ...params },
27+
});
28+
} catch (error) {
29+
return Promise.reject(error);
30+
}
31+
};
Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,64 @@
1+
// tslint:disable:no-any
2+
import { ItemNotFoundError } from '@js-items/foundation';
3+
import testItem from '@js-items/foundation/dist/functions/utils/testItem';
4+
import { config } from '../../utils/testConfig';
5+
import deleteItems from './index';
6+
7+
beforeEach(() => jest.clearAllMocks());
8+
19
describe('@deleteItems', () => {
2-
it('tests', () => {
3-
// TODO: implements tests
4-
expect(true).toBe(true);
10+
it('deletes items with no filter', async () => {
11+
const kyMock = jest.fn();
12+
13+
await deleteItems({
14+
...config,
15+
ky: () => Promise.resolve(kyMock) as any,
16+
})({});
17+
18+
expect(config.createFilter).toBeCalledWith({});
19+
20+
expect(kyMock).toBeCalledWith('', {
21+
method: 'delete',
22+
searchParams: { filter: JSON.stringify({}) },
23+
});
24+
});
25+
26+
it('deletes items with filter and custom search params', async () => {
27+
const kyMock = jest.fn();
28+
const filter = {
29+
id: { $eq: testItem.id },
30+
};
31+
const createFilterMock = jest.fn(() => filter);
32+
33+
await deleteItems({
34+
...config,
35+
createFilter: createFilterMock,
36+
deleteItemsOptions: () => ({ searchParams: { pretty: 'true' } }),
37+
ky: () => Promise.resolve(kyMock) as any,
38+
})({
39+
filter,
40+
});
41+
42+
expect(createFilterMock).toBeCalledWith(filter);
43+
44+
expect(kyMock).toBeCalledWith('', {
45+
method: 'delete',
46+
searchParams: { pretty: 'true', filter: JSON.stringify(filter) },
47+
});
48+
});
49+
50+
it('does not delete items', async () => {
51+
const error = new ItemNotFoundError('TestItem', testItem.id);
52+
53+
const facadeConfig = {
54+
...config,
55+
ky: jest.fn(() => Promise.reject(error)),
56+
};
57+
58+
try {
59+
await deleteItems(facadeConfig)({});
60+
} catch (e) {
61+
expect(e).toEqual(error);
62+
}
563
});
664
});

0 commit comments

Comments
 (0)