diff --git a/docs/facade.md b/docs/facade.md index ffb49acd..42e56ff2 100644 --- a/docs/facade.md +++ b/docs/facade.md @@ -6,11 +6,10 @@ The facade contains common functions for storage and retrieval of entities from - [createEntity](./functions.md#createentity) - [getEntities](./functions.md#getentities) - [getEntity](./functions.md#getentity) -- [overwriteEntity](./functions.md#overwriteentity) +- [replaceEntity](./functions.md#replaceentity) - [patchEntity](./functions.md#patchentity) - [removeEntities](./functions.md#removeentities) - [removeEntity](./functions.md#removeentity) -- [upsertEntity](./functions.md#upsertentity) The functions have some common options that they use. diff --git a/docs/functions.md b/docs/functions.md index 0d39f143..8327439e 100644 --- a/docs/functions.md +++ b/docs/functions.md @@ -6,11 +6,10 @@ The [facade](./facade.md) contains common functions for storage and retrieval of - [createEntity](#createentity) - [getEntities](#getentities) - [getEntity](#getentity) -- [overwriteEntity](#overwriteentity) +- [replaceEntity](#replaceentity) - [patchEntity](#patchentity) - [removeEntities](#removeentities) - [removeEntity](#removeentity) -- [upsertEntity](#upsertentity) ### countEntities Counts the number of entities that match the `filter` option. @@ -27,10 +26,19 @@ This package contains the [count entities tests](../src/tests/countEntities) and Creates a new entity using the `entity` option if no entity exists that matches the `id` option. ```ts -const { entity } = await facade.createEntity({ - id: 'example_id', - entity: { id: 'example_id', foo: 'bar' }, -}); +import ConflictingEntityError from 'js-entity-repos/core/dist/errors/ConflictingEntityError'; + +try { + const { entity } = await facade.createEntity({ + id: 'example_id', + entity: { id: 'example_id', foo: 'bar' }, + }); +} catch (err) { + if (err instanceof ConflictingEntityError) { + // An entity with the given id already exists. + } + throw err; +} ``` This package contains the [create entity tests](../src/tests/createEntity) and the [create entity signature](../src/signatures/CreateEntity.ts) for this function. @@ -59,36 +67,66 @@ const firstPage = await facade.getEntities({ This package contains the [get entities tests](../src/tests/getEntities) and the [get entities signature](../src/signatures/GetEntities.ts) for this function. ### getEntity -Retrieves a single entity that matches the `id` option. +Retrieves a single entity that matches the `id` and `filter` options. ```ts -const { entity } = await facade.getEntity({ - id: 'example_id', -}); +import MissingEntityError from 'js-entity-repos/core/dist/errors/MissingEntityError'; + +try { + const { entity } = await facade.getEntity({ + id: 'example_id', + filter: { foo: 'bar' }, + }); +} catch (err) { + if (err instanceof MissingEntityError) { + // No entity exists that matches the given id and filter options. + } + throw err; +} ``` This package contains the [get entity tests](../src/tests/getEntity) and the [get entity signature](../src/signatures/GetEntity.ts) for this function. -### overwriteEntity -For an entity that matches the `id` option, it changes all of an entity's properties using the `entity` option. +### replaceEntity +For an entity that matches the `id` and `filter` options, it changes all of an entity's properties using the `entity` option. ```ts -const { entity } = await facade.overwriteEntity({ - id: 'example_id', - entity: { id: 'example_id', foo: 'bar' }, -}); +import MissingEntityError from 'js-entity-repos/core/dist/errors/MissingEntityError'; + +try { + const { entity } = await facade.replaceEntity({ + id: 'example_id', + entity: { id: 'example_id', foo: 'bar' }, + filter: { foo: 'bar' }, + }); +} catch (err) { + if (err instanceof MissingEntityError) { + // No entity exists that matches the given id and filter options. + } + throw err; +} ``` -This package contains the [overwrite entity tests](../src/tests/overwriteEntity) and the [overwrite entity signature](../src/signatures/OverwriteEntity.ts) for this function. +This package contains the [replace entity tests](../src/tests/replaceEntity) and the [replace entity signature](../src/signatures/ReplaceEntity.ts) for this function. ### patchEntity -For an entity that matches the `id` option, it changes some of an entity's properties using the `patch` option. +For an entity that matches the `id` and `filter` options, it changes some of an entity's properties using the `patch` option. ```ts -const { entity } = await facade.patchEntity({ - id: 'example_id', - patch: { foo: 'bar' }, -}); +import MissingEntityError from 'js-entity-repos/core/dist/errors/MissingEntityError'; + +try { + const { entity } = await facade.patchEntity({ + id: 'example_id', + patch: { foo: 'bar' }, + filter: { foo: 'bar' }, + }); +} catch (err) { + if (err instanceof MissingEntityError) { + // No entity exists that matches the given id and filter options. + } + throw err; +} ``` This package contains the [patch entity tests](../src/tests/patchEntity) and the [patch entity signature](../src/signatures/PatchEntity.ts) for this function. @@ -105,24 +143,22 @@ await facade.removeEntities({ This package contains the [remove entities tests](../src/tests/removesEntities) and the [remove entities signature](../src/signatures/RemoveEntities.ts) for this function. ### removeEntity -Removes an entity that matches the `id` option. +Removes an entity that matches the `id` and `filter` options. ```ts -await facade.removeEntity({ - id: 'example_id', -}); +import MissingEntityError from 'js-entity-repos/core/dist/errors/MissingEntityError'; + +try { + await facade.removeEntity({ + id: 'example_id', + filter: { foo: 'bar' }, + }); +} catch (err) { + if (err instanceof MissingEntityError) { + // No entity exists that matches the given id and filter options. + } + throw err; +} ``` This package contains the [remove entity tests](../src/tests/removesEntity) and the [remove entity signature](../src/signatures/RemoveEntity.ts) for this function. - -### upsertEntity -Creates an entity when no entity exists that matches the `id` option. Otherwise, it overwrites all of the properties for an entity that matches the `id` option. - -```ts -await facade.upsertEntity({ - id: 'example_id', - entity: { id: 'example_id', foo: 'bar' }, -}); -``` - -This package contains the [upsert entity tests](../src/tests/upsertsEntity) and the [upsert entity signature](../src/signatures/UpsertEntity.ts) for this function. diff --git a/src/Facade.ts b/src/Facade.ts index ba29a28f..c687dbd4 100644 --- a/src/Facade.ts +++ b/src/Facade.ts @@ -2,21 +2,19 @@ import CountEntities from './signatures/CountEntities'; import CreateEntity from './signatures/CreateEntity'; import GetEntities from './signatures/GetEntities'; import GetEntity from './signatures/GetEntity'; -import OverwriteEntity from './signatures/OverwriteEntity'; import PatchEntity from './signatures/PatchEntity'; import RemoveEntities from './signatures/RemoveEntities'; import RemoveEntity from './signatures/RemoveEntity'; -import UpsertEntity from './signatures/UpsertEntity'; +import ReplaceEntity from './signatures/ReplaceEntity'; import Entity from './types/Entity'; export default interface Facade { readonly getEntity: GetEntity; readonly createEntity: CreateEntity; - readonly overwriteEntity: OverwriteEntity; + readonly replaceEntity: ReplaceEntity; readonly patchEntity: PatchEntity; - readonly removeEntity: RemoveEntity; + readonly removeEntity: RemoveEntity; readonly getEntities: GetEntities; readonly countEntities: CountEntities; readonly removeEntities: RemoveEntities; - readonly upsertEntity: UpsertEntity; } diff --git a/src/signatures/CountEntities.ts b/src/signatures/CountEntities.ts index d89803f9..a1577766 100644 --- a/src/signatures/CountEntities.ts +++ b/src/signatures/CountEntities.ts @@ -2,7 +2,7 @@ import Entity from '../types/Entity'; import Filter from '../types/Filter'; export interface Opts { - readonly filter: Filter; + readonly filter?: Filter; } export interface Result { diff --git a/src/signatures/GetEntities.ts b/src/signatures/GetEntities.ts index 3c011e57..9d8f26c4 100644 --- a/src/signatures/GetEntities.ts +++ b/src/signatures/GetEntities.ts @@ -5,9 +5,9 @@ import Pagination from '../types/Pagination'; import Sort from '../types/Sort'; export interface Opts { - readonly filter: Filter; - readonly sort: Sort; - readonly pagination: Pagination; + readonly filter?: Filter; + readonly sort?: Sort; + readonly pagination?: Pagination; } export interface Result { diff --git a/src/signatures/GetEntity.ts b/src/signatures/GetEntity.ts index 2106e957..78a8b2d3 100644 --- a/src/signatures/GetEntity.ts +++ b/src/signatures/GetEntity.ts @@ -1,13 +1,15 @@ import Entity from '../types/Entity'; +import Filter from '../types/Filter'; -export interface Opts { +export interface Opts { readonly id: string; + readonly filter?: Filter; } export interface Result { readonly entity: E; } -export type Signature = (opts: Opts) => Promise>; +export type Signature = (opts: Opts) => Promise>; export default Signature; diff --git a/src/signatures/PatchEntity.ts b/src/signatures/PatchEntity.ts index 8b74d5a6..fee842ac 100644 --- a/src/signatures/PatchEntity.ts +++ b/src/signatures/PatchEntity.ts @@ -1,8 +1,10 @@ import Entity from '../types/Entity'; +import Filter from '../types/Filter'; export interface Opts { readonly id: string; readonly patch: Partial; + readonly filter?: Filter; } export interface Result { diff --git a/src/signatures/RemoveEntities.ts b/src/signatures/RemoveEntities.ts index a6dece1e..5faf5920 100644 --- a/src/signatures/RemoveEntities.ts +++ b/src/signatures/RemoveEntities.ts @@ -2,7 +2,7 @@ import Entity from '../types/Entity'; import Filter from '../types/Filter'; export interface Opts { - readonly filter: Filter; + readonly filter?: Filter; } export type Result = void; diff --git a/src/signatures/RemoveEntity.ts b/src/signatures/RemoveEntity.ts index ae9701e9..fbf57852 100644 --- a/src/signatures/RemoveEntity.ts +++ b/src/signatures/RemoveEntity.ts @@ -1,9 +1,13 @@ -export interface Opts { +import Entity from '../types/Entity'; +import Filter from '../types/Filter'; + +export interface Opts { readonly id: string; + readonly filter?: Filter; } export type Result = void; -export type Signature = (opts: Opts) => Promise; +export type Signature = (opts: Opts) => Promise; export default Signature; diff --git a/src/signatures/OverwriteEntity.ts b/src/signatures/ReplaceEntity.ts similarity index 81% rename from src/signatures/OverwriteEntity.ts rename to src/signatures/ReplaceEntity.ts index 77af05ba..403e8c6c 100644 --- a/src/signatures/OverwriteEntity.ts +++ b/src/signatures/ReplaceEntity.ts @@ -1,8 +1,10 @@ import Entity from '../types/Entity'; +import Filter from '../types/Filter'; export interface Opts { readonly id: string; readonly entity: E; + readonly filter?: Filter; } export interface Result { diff --git a/src/signatures/UpsertEntity.ts b/src/signatures/UpsertEntity.ts deleted file mode 100644 index 77af05ba..00000000 --- a/src/signatures/UpsertEntity.ts +++ /dev/null @@ -1,14 +0,0 @@ -import Entity from '../types/Entity'; - -export interface Opts { - readonly id: string; - readonly entity: E; -} - -export interface Result { - readonly entity: E; -} - -export type Signature = (opts: Opts) => Promise>; - -export default Signature; diff --git a/src/tests/getEntities/filterTest.ts b/src/tests/getEntities/filterTest.ts index 8923e2a2..6379270b 100644 --- a/src/tests/getEntities/filterTest.ts +++ b/src/tests/getEntities/filterTest.ts @@ -1,26 +1,21 @@ import 'mocha'; // tslint:disable-line:no-import-side-effect import * as assert from 'power-assert'; import Facade from '../../Facade'; -import Pagination from '../../types/Pagination'; -import Sort from '../../types/Sort'; import filterTest, { firstEntity, secondEntity } from '../utils/filterTest'; import { TestEntity } from '../utils/testEntity'; export default (facade: Facade) => { - const sort: Sort = {}; - const pagination: Pagination = { cursor: undefined, forward: true, limit: 2 }; - filterTest({ assertAllEntitiesFilter: async (filter) => { - const actualResult = await facade.getEntities({ filter, sort, pagination }); + const actualResult = await facade.getEntities({ filter }); assert.deepEqual(actualResult.entities, [firstEntity, secondEntity]); }, assertFirstEntityFilter: async (filter) => { - const actualResult = await facade.getEntities({ filter, sort, pagination }); + const actualResult = await facade.getEntities({ filter }); assert.deepEqual(actualResult.entities, [firstEntity]); }, assertNoEntityFilter: async (filter) => { - const actualResult = await facade.getEntities({ filter, sort, pagination }); + const actualResult = await facade.getEntities({ filter }); assert.deepEqual(actualResult.entities, []); }, facade, diff --git a/src/tests/getEntities/paginationTest.ts b/src/tests/getEntities/paginationTest.ts index 6cbc9124..d1a2cbc7 100644 --- a/src/tests/getEntities/paginationTest.ts +++ b/src/tests/getEntities/paginationTest.ts @@ -2,9 +2,7 @@ import 'mocha'; // tslint:disable-line:no-import-side-effect import * as assert from 'power-assert'; import Facade from '../../Facade'; import Cursor from '../../types/Cursor'; -import Filter from '../../types/Filter'; import Pagination from '../../types/Pagination'; -import Sort from '../../types/Sort'; import { TestEntity, testEntity } from '../utils/testEntity'; export default (facade: Facade) => { @@ -12,8 +10,6 @@ export default (facade: Facade) => { const secondId = 'test_id_2'; const firstEntity = { ...testEntity, id: firstId }; const secondEntity = { ...testEntity, id: secondId }; - const sort: Sort = { id: true }; - const filter: Filter = {}; const createTestEntities = async () => { await facade.createEntity({ id: firstId, entity: firstEntity }); @@ -22,13 +18,19 @@ export default (facade: Facade) => { const paginate = (cursor: Cursor, forward: boolean) => { const pagination: Pagination = { cursor, forward, limit: 1 }; - return facade.getEntities({ filter, sort, pagination }); + return facade.getEntities({ pagination }); }; + it('should return all entities when pagination is not defined', async () => { + await createTestEntities(); + const result = await facade.getEntities({}); + assert.deepEqual(result.entities, [firstEntity]); + }); + it('should return first entity when there are two entities limitted to 1', async () => { await createTestEntities(); const pagination: Pagination = { cursor: undefined, forward: true, limit: 1 }; - const result = await facade.getEntities({ filter, sort, pagination }); + const result = await facade.getEntities({ pagination }); assert.deepEqual(result.entities, [firstEntity]); }); diff --git a/src/tests/getEntities/sortTest.ts b/src/tests/getEntities/sortTest.ts index db10795f..559d351f 100644 --- a/src/tests/getEntities/sortTest.ts +++ b/src/tests/getEntities/sortTest.ts @@ -1,8 +1,6 @@ import 'mocha'; // tslint:disable-line:no-import-side-effect import * as assert from 'power-assert'; import Facade from '../../Facade'; -import Filter from '../../types/Filter'; -import Pagination from '../../types/Pagination'; import Sort from '../../types/Sort'; import { TestEntity, testEntity } from '../utils/testEntity'; @@ -12,16 +10,19 @@ export default (facade: Facade) => { const firstEntity = { ...testEntity, id: firstId, stringProp: 'a', numberProp: 1 }; const secondEntity = { ...testEntity, id: secondId, stringProp: 'b', numberProp: 2 }; - const assertSort = async (sortedEntities: TestEntity[], sort: Sort) => { - const filter: Filter = {}; - const pagination: Pagination = { cursor: undefined, forward: true, limit: 2 }; - const actualResult = await facade.getEntities({ filter, sort, pagination }); - + const assertSort = async (sortedEntities: TestEntity[], sort?: Sort) => { + const actualResult = await facade.getEntities({ sort }); const actualEntities = actualResult.entities; const expectedEntities = sortedEntities; assert.deepEqual(actualEntities, expectedEntities); }; + it('should sort by ascending ids when sort is not defined', async () => { + await facade.createEntity({ id: firstId, entity: firstEntity }); + await facade.createEntity({ id: secondId, entity: secondEntity }); + await assertSort([firstEntity, secondEntity], undefined); + }); + it('should sort by one ascending property when entities are ordered', async () => { await facade.createEntity({ id: firstId, entity: firstEntity }); await facade.createEntity({ id: secondId, entity: secondEntity }); diff --git a/src/tests/getEntity/filterTest.ts b/src/tests/getEntity/filterTest.ts new file mode 100644 index 00000000..d4382d76 --- /dev/null +++ b/src/tests/getEntity/filterTest.ts @@ -0,0 +1,27 @@ +import * as assertRejects from 'assert-rejects'; +import 'mocha'; // tslint:disable-line:no-import-side-effect +import * as assert from 'power-assert'; +import MissingEntityError from '../../errors/MissingEntityError'; +import Facade from '../../Facade'; +import filterTest, { firstEntity, firstId, secondEntity, secondId } from '../utils/filterTest'; +import { TestEntity } from '../utils/testEntity'; + +export default (facade: Facade) => { + filterTest({ + assertAllEntitiesFilter: async (filter) => { + const firstEntityResult = await facade.getEntity({ id: firstId, filter }); + assert.deepEqual(firstEntityResult.entity, firstEntity); + const secondEntityResult = await facade.getEntity({ id: secondId, filter }); + assert.deepEqual(secondEntityResult.entity, secondEntity); + }, + assertFirstEntityFilter: async (filter) => { + const actualResult = await facade.getEntity({ id: firstId, filter }); + assert.deepEqual(actualResult.entity, firstEntity); + }, + assertNoEntityFilter: async (filter) => { + const promise = facade.getEntity({ id: firstId, filter }); + await assertRejects(promise, MissingEntityError); + }, + facade, + }); +}; diff --git a/src/tests/getEntity/idTest.ts b/src/tests/getEntity/idTest.ts new file mode 100644 index 00000000..4ff7b7e0 --- /dev/null +++ b/src/tests/getEntity/idTest.ts @@ -0,0 +1,19 @@ +import * as assertRejects from 'assert-rejects'; +import 'mocha'; // tslint:disable-line:no-import-side-effect +import * as assert from 'power-assert'; +import MissingEntityError from '../../errors/MissingEntityError'; +import Facade from '../../Facade'; +import { TestEntity, testEntity, testId } from '../utils/testEntity'; + +export default (facade: Facade) => { + it('should error when identifier does not exist', async () => { + const promise = facade.getEntity({ id: testId }); + await assertRejects(promise, MissingEntityError); + }); + + it('should not error when identifier does exist', async () => { + await facade.createEntity({ id: testId, entity: testEntity }); + const { entity: retrievedEntity } = await facade.getEntity({ id: testId }); + assert.deepEqual(retrievedEntity, testEntity); + }); +}; diff --git a/src/tests/getEntity/test.ts b/src/tests/getEntity/test.ts index 92a9e077..42ca1a1c 100644 --- a/src/tests/getEntity/test.ts +++ b/src/tests/getEntity/test.ts @@ -1,21 +1,12 @@ -import * as assertRejects from 'assert-rejects'; import 'mocha'; // tslint:disable-line:no-import-side-effect -import * as assert from 'power-assert'; -import MissingEntityError from '../../errors/MissingEntityError'; import Facade from '../../Facade'; -import { TestEntity, testEntity, testId } from '../utils/testEntity'; +import { TestEntity } from '../utils/testEntity'; +import filterTest from './filterTest'; +import idTest from './idTest'; export default (facade: Facade) => { describe('getEntity', () => { - it('should error when identifier does not exist', async () => { - const promise = facade.getEntity({ id: testId }); - await assertRejects(promise, MissingEntityError); - }); - - it('should not error when identifier does exist', async () => { - await facade.createEntity({ id: testId, entity: testEntity }); - const { entity: retrievedEntity } = await facade.getEntity({ id: testId }); - assert.deepEqual(retrievedEntity, testEntity); - }); + idTest(facade); + filterTest(facade); }); }; diff --git a/src/tests/index.ts b/src/tests/index.ts index 497822ab..911dafd6 100644 --- a/src/tests/index.ts +++ b/src/tests/index.ts @@ -4,11 +4,10 @@ import countEntitiesTest from './countEntities/test'; import createEntityTest from './createEntity/test'; import getEntitiesTest from './getEntities/test'; import getEntityTest from './getEntity/test'; -import overwriteEntityTest from './overwriteEntity/test'; import patchEntityTest from './patchEntity/test'; import removeEntitiesTest from './removeEntities/test'; import removeEntityTest from './removeEntity/test'; -import upsertEntityTest from './upsertEntity/test'; +import replaceEntityTest from './replaceEntity/test'; import { TestEntity } from './utils/testEntity'; export default (facade: Facade) => { @@ -20,11 +19,10 @@ export default (facade: Facade) => { createEntityTest(facade); getEntityTest(facade); removeEntityTest(facade); - overwriteEntityTest(facade); + replaceEntityTest(facade); patchEntityTest(facade); countEntitiesTest(facade); getEntitiesTest(facade); removeEntitiesTest(facade); - upsertEntityTest(facade); }); }; diff --git a/src/tests/overwriteEntity/test.ts b/src/tests/overwriteEntity/test.ts deleted file mode 100644 index 763fc5fb..00000000 --- a/src/tests/overwriteEntity/test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import * as assertRejects from 'assert-rejects'; -import 'mocha'; // tslint:disable-line:no-import-side-effect -import * as assert from 'power-assert'; -import MissingEntityError from '../../errors/MissingEntityError'; -import Facade from '../../Facade'; -import { TestEntity, testEntity, testId } from '../utils/testEntity'; - -export default (facade: Facade) => { - describe('overwriteEntity', () => { - it('should error when identifier does not exist', async () => { - const promise = facade.overwriteEntity({ id: testId, entity: testEntity }); - await assertRejects(promise, MissingEntityError); - }); - - it('should overwrite when identifier does exist', async () => { - const testOverwrite: TestEntity = { - booleanProp: false, - id: testId, - numberProp: 2, - stringProp: 'test_string_prop_overwrite', - }; - await facade.createEntity({ id: testId, entity: testEntity }); - const { entity: overwrittenEntity } = await facade.overwriteEntity({ - entity: testOverwrite, - id: testId, - }); - const { entity: retrievedEntity } = await facade.getEntity({ id: testId }); - assert.deepEqual(overwrittenEntity, testOverwrite); - assert.deepEqual(retrievedEntity, testOverwrite); - }); - }); -}; diff --git a/src/tests/patchEntity/filterTest.ts b/src/tests/patchEntity/filterTest.ts new file mode 100644 index 00000000..1eda64c7 --- /dev/null +++ b/src/tests/patchEntity/filterTest.ts @@ -0,0 +1,43 @@ +import * as assertRejects from 'assert-rejects'; +import 'mocha'; // tslint:disable-line:no-import-side-effect +import * as assert from 'power-assert'; +import MissingEntityError from '../../errors/MissingEntityError'; +import Facade from '../../Facade'; +import filterTest, { firstEntity, firstId, secondEntity, secondId } from '../utils/filterTest'; +import { TestEntity } from '../utils/testEntity'; + +export default (facade: Facade) => { + filterTest({ + assertAllEntitiesFilter: async (filter) => { + const firstEntityResult = await facade.patchEntity({ + filter, + id: firstId, + patch: firstEntity, + }); + assert.deepEqual(firstEntityResult.entity, firstEntity); + const secondEntityResult = await facade.patchEntity({ + filter, + id: secondId, + patch: secondEntity, + }); + assert.deepEqual(secondEntityResult.entity, secondEntity); + }, + assertFirstEntityFilter: async (filter) => { + const actualResult = await facade.patchEntity({ + filter, + id: firstId, + patch: firstEntity, + }); + assert.deepEqual(actualResult.entity, firstEntity); + }, + assertNoEntityFilter: async (filter) => { + const promise = facade.patchEntity({ + filter, + id: firstId, + patch: firstEntity, + }); + await assertRejects(promise, MissingEntityError); + }, + facade, + }); +}; diff --git a/src/tests/patchEntity/idTest.ts b/src/tests/patchEntity/idTest.ts new file mode 100644 index 00000000..5f022a45 --- /dev/null +++ b/src/tests/patchEntity/idTest.ts @@ -0,0 +1,42 @@ +import * as assertRejects from 'assert-rejects'; +import 'mocha'; // tslint:disable-line:no-import-side-effect +import * as assert from 'power-assert'; +import MissingEntityError from '../../errors/MissingEntityError'; +import Facade from '../../Facade'; +import { TestEntity, testEntity, testId } from '../utils/testEntity'; + +export default (facade: Facade) => { + const assertPatch = async (testPatch: Partial) => { + const { entity: patchedEntity } = await facade.patchEntity({ + id: testId, + patch: testPatch, + }); + const { entity: retrievedEntity } = await facade.getEntity({ id: testId }); + const expectedEntity = { ...testEntity, ...testPatch }; + assert.deepEqual(patchedEntity, expectedEntity); + assert.deepEqual(retrievedEntity, expectedEntity); + }; + + it('should error when identifier does not exist', async () => { + const promise = facade.patchEntity({ id: testId, patch: testEntity }); + await assertRejects(promise, MissingEntityError); + }); + + it('should patch when patching one entity property', async () => { + const testPatch: Partial = { + stringProp: 'test_string_prop_patch', + }; + await facade.createEntity({ id: testId, entity: testEntity }); + await assertPatch(testPatch); + }); + + it('should patch when patching all entity properties', async () => { + const testPatch: Partial = { + booleanProp: false, + numberProp: 2, + stringProp: 'test_string_prop_patch', + }; + await facade.createEntity({ id: testId, entity: testEntity }); + await assertPatch(testPatch); + }); +}; diff --git a/src/tests/patchEntity/test.ts b/src/tests/patchEntity/test.ts index b74a9bbc..0c7e62d9 100644 --- a/src/tests/patchEntity/test.ts +++ b/src/tests/patchEntity/test.ts @@ -1,44 +1,12 @@ -import * as assertRejects from 'assert-rejects'; import 'mocha'; // tslint:disable-line:no-import-side-effect -import * as assert from 'power-assert'; -import MissingEntityError from '../../errors/MissingEntityError'; import Facade from '../../Facade'; -import { TestEntity, testEntity, testId } from '../utils/testEntity'; +import { TestEntity } from '../utils/testEntity'; +import filterTest from './filterTest'; +import idTest from './idTest'; export default (facade: Facade) => { describe('patchEntity', () => { - const assertPatch = async (testPatch: Partial) => { - const { entity: patchedEntity } = await facade.patchEntity({ - id: testId, - patch: testPatch, - }); - const { entity: retrievedEntity } = await facade.getEntity({ id: testId }); - const expectedEntity = { ...testEntity, ...testPatch }; - assert.deepEqual(patchedEntity, expectedEntity); - assert.deepEqual(retrievedEntity, expectedEntity); - }; - - it('should error when identifier does not exist', async () => { - const promise = facade.patchEntity({ id: testId, patch: testEntity }); - await assertRejects(promise, MissingEntityError); - }); - - it('should patch when patching one entity property', async () => { - const testPatch: Partial = { - stringProp: 'test_string_prop_patch', - }; - await facade.createEntity({ id: testId, entity: testEntity }); - await assertPatch(testPatch); - }); - - it('should patch when patching all entity properties', async () => { - const testPatch: Partial = { - booleanProp: false, - numberProp: 2, - stringProp: 'test_string_prop_patch', - }; - await facade.createEntity({ id: testId, entity: testEntity }); - await assertPatch(testPatch); - }); + idTest(facade); + filterTest(facade); }); }; diff --git a/src/tests/removeEntities/test.ts b/src/tests/removeEntities/test.ts index f6afc17f..6945386e 100644 --- a/src/tests/removeEntities/test.ts +++ b/src/tests/removeEntities/test.ts @@ -1,30 +1,25 @@ import 'mocha'; // tslint:disable-line:no-import-side-effect import * as assert from 'power-assert'; import Facade from '../../Facade'; -import Pagination from '../../types/Pagination'; -import Sort from '../../types/Sort'; import filterTest, { firstEntity, secondEntity } from '../utils/filterTest'; import { TestEntity } from '../utils/testEntity'; export default (facade: Facade) => { describe('removeEntities', () => { - const sort: Sort = {}; - const pagination: Pagination = { cursor: undefined, forward: true, limit: 2 }; - filterTest({ assertAllEntitiesFilter: async (filter) => { await facade.removeEntities({ filter }); - const actualResult = await facade.getEntities({ filter: {}, sort, pagination }); + const actualResult = await facade.getEntities({}); assert.deepEqual(actualResult.entities, []); }, assertFirstEntityFilter: async (filter) => { await facade.removeEntities({ filter }); - const actualResult = await facade.getEntities({ filter: {}, sort, pagination }); + const actualResult = await facade.getEntities({}); assert.deepEqual(actualResult.entities, [secondEntity]); }, assertNoEntityFilter: async (filter) => { await facade.removeEntities({ filter }); - const actualResult = await facade.getEntities({ filter: {}, sort, pagination }); + const actualResult = await facade.getEntities({}); assert.deepEqual(actualResult.entities, [firstEntity, secondEntity]); }, facade, diff --git a/src/tests/removeEntity/filterTest.ts b/src/tests/removeEntity/filterTest.ts new file mode 100644 index 00000000..72fa915b --- /dev/null +++ b/src/tests/removeEntity/filterTest.ts @@ -0,0 +1,29 @@ +import * as assertRejects from 'assert-rejects'; +import 'mocha'; // tslint:disable-line:no-import-side-effect +import MissingEntityError from '../../errors/MissingEntityError'; +import Facade from '../../Facade'; +import filterTest, { firstId, secondId } from '../utils/filterTest'; +import { TestEntity } from '../utils/testEntity'; + +export default (facade: Facade) => { + filterTest({ + assertAllEntitiesFilter: async (filter) => { + await facade.removeEntity({ filter, id: firstId }); + await facade.removeEntity({ filter, id: secondId }); + const firstPromise = facade.getEntity({ id: firstId }); + await assertRejects(firstPromise, MissingEntityError); + const secondPromise = facade.getEntity({ id: secondId }); + await assertRejects(secondPromise, MissingEntityError); + }, + assertFirstEntityFilter: async (filter) => { + await facade.removeEntity({ filter, id: firstId }); + const promise = facade.getEntity({ id: firstId }); + await assertRejects(promise, MissingEntityError); + }, + assertNoEntityFilter: async (filter) => { + const promise = facade.removeEntity({ filter, id: firstId }); + await assertRejects(promise, MissingEntityError); + }, + facade, + }); +}; diff --git a/src/tests/removeEntity/idTest.ts b/src/tests/removeEntity/idTest.ts new file mode 100644 index 00000000..549b0c3f --- /dev/null +++ b/src/tests/removeEntity/idTest.ts @@ -0,0 +1,19 @@ +import * as assertRejects from 'assert-rejects'; +import 'mocha'; // tslint:disable-line:no-import-side-effect +import MissingEntityError from '../../errors/MissingEntityError'; +import Facade from '../../Facade'; +import { TestEntity, testEntity, testId } from '../utils/testEntity'; + +export default (facade: Facade) => { + it('should error when identifier does not exist', async () => { + const promise = facade.removeEntity({ id: testId }); + await assertRejects(promise, MissingEntityError); + }); + + it('should not error when identifier does exist', async () => { + await facade.createEntity({ id: testId, entity: testEntity }); + await facade.removeEntity({ id: testId }); + const promise = facade.getEntity({ id: testId }); + await assertRejects(promise, MissingEntityError); + }); +}; diff --git a/src/tests/removeEntity/test.ts b/src/tests/removeEntity/test.ts index ab872e7e..b3a98b09 100644 --- a/src/tests/removeEntity/test.ts +++ b/src/tests/removeEntity/test.ts @@ -1,21 +1,12 @@ -import * as assertRejects from 'assert-rejects'; import 'mocha'; // tslint:disable-line:no-import-side-effect -import MissingEntityError from '../../errors/MissingEntityError'; import Facade from '../../Facade'; -import { TestEntity, testEntity, testId } from '../utils/testEntity'; +import { TestEntity } from '../utils/testEntity'; +import filterTest from './filterTest'; +import idTest from './idTest'; export default (facade: Facade) => { describe('removeEntity', () => { - it('should error when identifier does not exist', async () => { - const promise = facade.removeEntity({ id: testId }); - await assertRejects(promise, MissingEntityError); - }); - - it('should not error when identifier does exist', async () => { - await facade.createEntity({ id: testId, entity: testEntity }); - await facade.removeEntity({ id: testId }); - const promise = facade.getEntity({ id: testId }); - await assertRejects(promise, MissingEntityError); - }); + idTest(facade); + filterTest(facade); }); }; diff --git a/src/tests/replaceEntity/filterTest.ts b/src/tests/replaceEntity/filterTest.ts new file mode 100644 index 00000000..d3cb8d86 --- /dev/null +++ b/src/tests/replaceEntity/filterTest.ts @@ -0,0 +1,43 @@ +import * as assertRejects from 'assert-rejects'; +import 'mocha'; // tslint:disable-line:no-import-side-effect +import * as assert from 'power-assert'; +import MissingEntityError from '../../errors/MissingEntityError'; +import Facade from '../../Facade'; +import filterTest, { firstEntity, firstId, secondEntity, secondId } from '../utils/filterTest'; +import { TestEntity } from '../utils/testEntity'; + +export default (facade: Facade) => { + filterTest({ + assertAllEntitiesFilter: async (filter) => { + const firstEntityResult = await facade.replaceEntity({ + entity: firstEntity, + filter, + id: firstId, + }); + assert.deepEqual(firstEntityResult.entity, firstEntity); + const secondEntityResult = await facade.replaceEntity({ + entity: secondEntity, + filter, + id: secondId, + }); + assert.deepEqual(secondEntityResult.entity, secondEntity); + }, + assertFirstEntityFilter: async (filter) => { + const actualResult = await facade.replaceEntity({ + entity: firstEntity, + filter, + id: firstId, + }); + assert.deepEqual(actualResult.entity, firstEntity); + }, + assertNoEntityFilter: async (filter) => { + const promise = facade.replaceEntity({ + entity: firstEntity, + filter, + id: firstId, + }); + await assertRejects(promise, MissingEntityError); + }, + facade, + }); +}; diff --git a/src/tests/replaceEntity/idTest.ts b/src/tests/replaceEntity/idTest.ts new file mode 100644 index 00000000..b5dae97e --- /dev/null +++ b/src/tests/replaceEntity/idTest.ts @@ -0,0 +1,30 @@ +import * as assertRejects from 'assert-rejects'; +import 'mocha'; // tslint:disable-line:no-import-side-effect +import * as assert from 'power-assert'; +import MissingEntityError from '../../errors/MissingEntityError'; +import Facade from '../../Facade'; +import { TestEntity, testEntity, testId } from '../utils/testEntity'; + +export default (facade: Facade) => { + it('should error when identifier does not exist', async () => { + const promise = facade.replaceEntity({ id: testId, entity: testEntity }); + await assertRejects(promise, MissingEntityError); + }); + + it('should replace when identifier does exist', async () => { + const replacement: TestEntity = { + booleanProp: false, + id: testId, + numberProp: 2, + stringProp: 'test_string_prop_replace', + }; + await facade.createEntity({ id: testId, entity: testEntity }); + const { entity: replacedEntity } = await facade.replaceEntity({ + entity: replacement, + id: testId, + }); + const { entity: retrievedEntity } = await facade.getEntity({ id: testId }); + assert.deepEqual(replacedEntity, replacement); + assert.deepEqual(retrievedEntity, replacement); + }); +}; diff --git a/src/tests/replaceEntity/test.ts b/src/tests/replaceEntity/test.ts new file mode 100644 index 00000000..b8c48e65 --- /dev/null +++ b/src/tests/replaceEntity/test.ts @@ -0,0 +1,12 @@ +import 'mocha'; // tslint:disable-line:no-import-side-effect +import Facade from '../../Facade'; +import { TestEntity } from '../utils/testEntity'; +import filterTest from './filterTest'; +import idTest from './idTest'; + +export default (facade: Facade) => { + describe('replaceEntity', () => { + idTest(facade); + filterTest(facade); + }); +}; diff --git a/src/tests/upsertEntity/test.ts b/src/tests/upsertEntity/test.ts deleted file mode 100644 index a11cf6f0..00000000 --- a/src/tests/upsertEntity/test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import 'mocha'; // tslint:disable-line:no-import-side-effect -import * as assert from 'power-assert'; -import Facade from '../../Facade'; -import { TestEntity, testEntity, testId } from '../utils/testEntity'; - -export default (facade: Facade) => { - describe('upsertEntity', () => { - it('should create when identifier does not exist', async () => { - const { entity: createdEntity } = await facade.upsertEntity({ - entity: testEntity, - id: testId, - }); - const { entity: retrievedEntity } = await facade.getEntity({ id: testId }); - assert.deepEqual(createdEntity, testEntity); - assert.deepEqual(retrievedEntity, testEntity); - }); - - it('should overwrite when identifier does exist', async () => { - const testOverwrite: TestEntity = { - booleanProp: false, - id: testId, - numberProp: 2, - stringProp: 'test_string_prop_overwrite', - }; - await facade.createEntity({ id: testId, entity: testEntity }); - const { entity: overwrittenEntity } = await facade.upsertEntity({ - entity: testOverwrite, - id: testId, - }); - const { entity: retrievedEntity } = await facade.getEntity({ id: testId }); - assert.deepEqual(overwrittenEntity, testOverwrite); - assert.deepEqual(retrievedEntity, testOverwrite); - }); - }); -}; diff --git a/src/tests/utils/filterTest.ts b/src/tests/utils/filterTest.ts index d00f0e45..6d559bad 100644 --- a/src/tests/utils/filterTest.ts +++ b/src/tests/utils/filterTest.ts @@ -3,7 +3,7 @@ import Facade from '../../Facade'; import Filter from '../../types/Filter'; import { TestEntity, testEntity } from '../utils/testEntity'; -export type FilterAsserter = (filter: Filter) => Promise; +export type FilterAsserter = (filter?: Filter) => Promise; export interface Opts { readonly facade: Facade; @@ -11,8 +11,8 @@ export interface Opts { readonly assertNoEntityFilter: FilterAsserter; readonly assertAllEntitiesFilter: FilterAsserter; } -const firstId = 'test_id_1'; -const secondId = 'test_id_2'; +export const firstId = 'test_id_1'; +export const secondId = 'test_id_2'; export const firstEntity = { ...testEntity, id: firstId, stringProp: 'a', numberProp: 1 }; export const secondEntity = { ...testEntity, id: secondId, stringProp: 'b', numberProp: 2 }; @@ -22,12 +22,17 @@ export default (opts: Opts) => { await opts.facade.createEntity({ id: secondId, entity: secondEntity }); }; + it('should not filter when filter is not defined', async () => { + await createTestEntities(); + await opts.assertAllEntitiesFilter(undefined); + }); + it('should not filter when using no filter', async () => { await createTestEntities(); await opts.assertAllEntitiesFilter({}); }); - it('should not filter when using no filter', async () => { + it('should return no entities when using a filter matching none', async () => { await createTestEntities(); await opts.assertNoEntityFilter({ stringProp: 'c' }); });