From 72cd371961ce8df681f2d512a95a78d521f3e2e3 Mon Sep 17 00:00:00 2001 From: Ryan Smith <0ryansmith1994@gmail.com> Date: Sun, 11 Feb 2018 21:18:12 +0000 Subject: [PATCH] fix(deps): Updates core to 6.0.2. --- package-lock.json | 75 +++++++++++++------------ package.json | 4 +- readme.md | 41 ++++++++------ src/Config.ts | 11 ---- src/FacadeConfig.ts | 17 ++++++ src/FactoryConfig.ts | 17 ++++++ src/facade.ts | 25 --------- src/{facade.test.ts => factory.test.ts} | 13 ++--- src/factory.ts | 33 +++++++++++ src/functions/countEntities.ts | 9 +-- src/functions/createEntity.ts | 9 +-- src/functions/getEntities.ts | 22 ++++++-- src/functions/getEntity.ts | 13 +++-- src/functions/overwriteEntity.ts | 12 ---- src/functions/patchEntity.ts | 16 ++++-- src/functions/removeEntities.ts | 12 ++-- src/functions/removeEntity.ts | 13 +++-- src/functions/replaceEntity.ts | 16 ++++++ src/functions/upsertEntity.ts | 19 ------- src/utils/connectToDb.ts | 5 +- src/utils/constructIdFilter.ts | 16 ++++++ src/utils/filterEntities.ts | 28 ++++++--- 22 files changed, 252 insertions(+), 174 deletions(-) delete mode 100644 src/Config.ts create mode 100644 src/FacadeConfig.ts create mode 100644 src/FactoryConfig.ts delete mode 100644 src/facade.ts rename src/{facade.test.ts => factory.test.ts} (64%) create mode 100644 src/factory.ts delete mode 100644 src/functions/overwriteEntity.ts create mode 100644 src/functions/replaceEntity.ts delete mode 100644 src/functions/upsertEntity.ts create mode 100644 src/utils/constructIdFilter.ts diff --git a/package-lock.json b/package-lock.json index af8c8cda6..0a98d6057 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,25 +22,25 @@ } }, "@ht2-labs/typescript-project": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@ht2-labs/typescript-project/-/typescript-project-1.0.0.tgz", - "integrity": "sha512-/cqQYDdon/O7Q0+VJJ+cbUWMlHDTw3FY+kaDblWGp+orpMcoO+yjZnG0a2MF7P8IVu+9U+fXN5W7Jq5O45VSCA==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@ht2-labs/typescript-project/-/typescript-project-1.0.9.tgz", + "integrity": "sha512-5CtWNSbOsuEleUn9jMI1y09Qpmk9cAKsfxPGkc70ubcb/exdTFne0j11Dtr/qcdFr9W8Oz6ydgtnuk+xh3721g==", "dev": true, "requires": { - "tslint": "5.8.0", - "tslint-consistent-codestyle": "1.11.0", - "tslint-immutable": "4.4.0", - "typescript": "2.6.2" + "tslint": "5.9.1", + "tslint-consistent-codestyle": "1.11.1", + "tslint-immutable": "4.5.1", + "typescript": "2.7.1" } }, "@js-entity-repos/core": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@js-entity-repos/core/-/core-4.1.2.tgz", - "integrity": "sha512-prz8Yy2GFe2xJLJYeUfaAZRoecNcVZFVW3weorn42IVwey+pWnjJxL6MHBEmeJOpcWnVMiaw8dxefvk0ulUUuQ==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@js-entity-repos/core/-/core-6.0.2.tgz", + "integrity": "sha512-rt9hDbLnq6sKemo/Pn48mATUzSPgwRLWPcOOSsNdVkhppKEa3a/Nuej4MxAqZVNmzploBYZzlu7HZ3gfmWQrrw==", "requires": { "btoa": "1.1.2", "lodash": "4.17.4", - "make-error": "1.3.0" + "make-error": "1.3.3" } }, "@semantic-release/commit-analyzer": { @@ -2739,9 +2739,9 @@ } }, "make-error": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.0.tgz", - "integrity": "sha1-Uq06M5zPEM5itAQLcI/nByRLi5Y=" + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.3.tgz", + "integrity": "sha512-j3dZCri3cCd23wgPqK/0/KvTN8R+W6fXDqQe8BNLbTpONjbA8SPaRr+q0BQq9bx3Q/+g68/gDIh9FW3by702Tg==" }, "map-cache": { "version": "0.2.2", @@ -6292,15 +6292,15 @@ "dev": true }, "tslib": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.8.1.tgz", - "integrity": "sha1-aUavLR1lGnsYY7Ux1uWvpBqkTqw=", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz", + "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==", "dev": true }, "tslint": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.8.0.tgz", - "integrity": "sha1-H0mtWy53x2w69N3K5VKuTjYS6xM=", + "version": "5.9.1", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.9.1.tgz", + "integrity": "sha1-ElX4ej/1frCw4fDmEKi0dIBGya4=", "dev": true, "requires": { "babel-code-frame": "6.26.0", @@ -6309,36 +6309,37 @@ "commander": "2.12.2", "diff": "3.4.0", "glob": "7.1.2", + "js-yaml": "3.10.0", "minimatch": "3.0.4", "resolve": "1.5.0", "semver": "5.4.1", - "tslib": "1.8.1", - "tsutils": "2.14.0" + "tslib": "1.9.0", + "tsutils": "2.21.1" } }, "tslint-consistent-codestyle": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/tslint-consistent-codestyle/-/tslint-consistent-codestyle-1.11.0.tgz", - "integrity": "sha512-8vXW3UiM6SF68KQ9rjiyhpRV3B5VzVRCUaZsdArbS3sWSV57yqRt2OoQoJGcodMxeh5lOCTaT82UKbNHv86KCA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslint-consistent-codestyle/-/tslint-consistent-codestyle-1.11.1.tgz", + "integrity": "sha512-wLu+Ct8x4mBmVkuhEiNAnUBkxchMV2Le0ikBsST5HnKbGlm3K4RSpXCBSI1VtJDk748W2I5hDzgsInawLdnxwQ==", "dev": true, "requires": { - "tslib": "1.8.1", - "tsutils": "2.14.0" + "tslib": "1.9.0", + "tsutils": "2.21.1" } }, "tslint-immutable": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/tslint-immutable/-/tslint-immutable-4.4.0.tgz", - "integrity": "sha512-WHNXczBTqp2wb5RMK0/8ZmroJ7TnYmSOCJS5c1uMOe7/BsBWFyYeTMmxpDtLTYngArJB/QecRnxxBM3oav/qGg==", + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/tslint-immutable/-/tslint-immutable-4.5.1.tgz", + "integrity": "sha512-rDVZEylmKjuqKlIqsOq7M7wjSMHs/tKP84FisOLhCQVrY80/eviJSn+NPkhdU/mr5YrfqhwiAR72eWhDp5Z/QQ==", "dev": true }, "tsutils": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.14.0.tgz", - "integrity": "sha512-f6axSMV0RoUufiKiRQgmRlN1c+Ag+mDaZjcd6bHdvplT/zyhuMCGqw3pJS8s3+0x4EVkdoQajs9PchdDZlguvw==", + "version": "2.21.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.21.1.tgz", + "integrity": "sha512-heMkdeQ9iUc90ynfiNo5Y+GXrEEGy86KMvnSTfHO+Q40AuNQ1lZGXcv58fuU9XTUxI0V7YIN9xPN+CO9b1Gn3w==", "dev": true, "requires": { - "tslib": "1.8.1" + "tslib": "1.9.0" } }, "tunnel-agent": { @@ -6370,9 +6371,9 @@ "dev": true }, "typescript": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.2.tgz", - "integrity": "sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q=", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.7.1.tgz", + "integrity": "sha512-bqB1yS6o9TNA9ZC/MJxM0FZzPnZdtHj0xWK/IZ5khzVqdpGul/R/EIiHRgFXlwTD7PSIaYVnGKq1QgMCu2mnqw==", "dev": true }, "uglify-js": { diff --git a/package.json b/package.json index 88918b326..242af4e5e 100644 --- a/package.json +++ b/package.json @@ -25,13 +25,13 @@ "check-coverage": true }, "dependencies": { - "@js-entity-repos/core": "^4.1.2", + "@js-entity-repos/core": "^6.0.2", "knex": "^0.14.2", "lodash": "^4.17.4" }, "devDependencies": { "@ht2-labs/semantic-release": "1.0.14", - "@ht2-labs/typescript-project": "1.0.0", + "@ht2-labs/typescript-project": "1.0.9", "@types/dotenv": "^4.0.2", "@types/knex": "0.0.67", "@types/lodash": "^4.14.91", diff --git a/readme.md b/readme.md index c3370757d..8f81346a5 100644 --- a/readme.md +++ b/readme.md @@ -4,39 +4,45 @@ ### Usage 1. Install it with `npm i @js-entity-repos/knex`. 1. For each entity you will need to do the following. - 1. [Create Id and Entity interfaces](#id-and-entity-interface). - 1. [Create a facade config](#facade-config). - 1. [Construct the facade with the config and interfaces](#calling-the-facade). + 1. [Create an Entity interfaces](#entity-interface). + 1. [Create a factory config](#factory-config). + 1. [Construct the facade](#construct-the-facade). 1. [Use the facade](https://github.com/js-entity-repos/core/blob/master/docs/facade.md). -### Id and Entity Interface +### Entity Interface ```ts -export interface TodoId { - readonly id: string; -} +import Entity from '@js-entity-repos/core/dist/types/Entity'; -export interface TodoEntity extends TodoId { +export interface TodoEntity extends Entity { readonly description: string; readonly completed: boolean; } ``` -### Facade Config +### Factory Config ```ts -import FacadeConfig from '@js-entity-repos/knex/dist/Config'; +import FactoryConfig from '@js-entity-repos/knex/dist/FactoryConfig'; import connectToDb from '@js-entity-repos/knex/dist/utils/connectToDb'; -const todoFacadeConfig: FacadeConfig = { - constructDocument: (id, patch) => { - // Converts an entity to a document for the database. - return { ...patch, ...id } +const todoFactoryConfig: FactoryConfig = { + constructDocument: (patch) => { + // Optional property that converts an entity to a document for the database. + return patch; }, constructEntity: (document) => { - // Converts a document from the database to an entity. + // Optional property that converts a document from the database to an entity. return document; }, + constructFilter: (filter) => { + // Optional property that converts an entity filter to a filter for the DB. + return filter; + }, + constructSort: (sort) => { + // Optional property that converts an entity sort to a sort for the DB. + return sort; + }. db: connectToDb({ client: 'mysql', connection: { @@ -46,6 +52,7 @@ const todoFacadeConfig: FacadeConfig = { user: 'todouser', }, }), + defaultPaginationLimit: 100, // Optional property. entityName: 'todo', tableName: 'todos', }; @@ -54,7 +61,7 @@ const todoFacadeConfig: FacadeConfig = { ### Construct the Facade ```ts -import facade from '@js-entity-repos/knex/dist/facade'; +import factory from '@js-entity-repos/knex/dist/factory'; -const todosFacade = facade(todoFacadeConfig); +const todosFacade = factory(todoFactoryConfig); ``` diff --git a/src/Config.ts b/src/Config.ts deleted file mode 100644 index 7effa871a..000000000 --- a/src/Config.ts +++ /dev/null @@ -1,11 +0,0 @@ -import * as knex from 'knex'; - -export type Document = any; - -export default interface Config { - readonly constructDocument: (id: Id, patch: Partial) => Document; - readonly constructEntity: (document: Document) => Entity; - readonly db: knex; - readonly entityName: string; - readonly tableName: string; -} diff --git a/src/FacadeConfig.ts b/src/FacadeConfig.ts new file mode 100644 index 000000000..f26d1fc81 --- /dev/null +++ b/src/FacadeConfig.ts @@ -0,0 +1,17 @@ +import Entity from '@js-entity-repos/core/dist/types/Entity'; +import Filter from '@js-entity-repos/core/dist/types/Filter'; +import Sort from '@js-entity-repos/core/dist/types/Sort'; +import * as knex from 'knex'; + +export type Document = any; + +export default interface FacadeConfig { + readonly constructDocument: (patch: Partial) => Document; + readonly constructEntity: (document: Document) => E; + readonly constructFilter: (filter: Filter) => any; + readonly constructSort: (sort: Sort) => any; + readonly db: () => Promise; + readonly defaultPaginationLimit: number; + readonly entityName: string; + readonly tableName: string; +} diff --git a/src/FactoryConfig.ts b/src/FactoryConfig.ts new file mode 100644 index 000000000..ba5ec3207 --- /dev/null +++ b/src/FactoryConfig.ts @@ -0,0 +1,17 @@ +import Entity from '@js-entity-repos/core/dist/types/Entity'; +import Filter from '@js-entity-repos/core/dist/types/Filter'; +import Sort from '@js-entity-repos/core/dist/types/Sort'; +import * as knex from 'knex'; + +export type Document = any; + +export default interface FacadeConfig { + readonly constructDocument?: (patch: Partial) => Document; + readonly constructEntity?: (document: Document) => E; + readonly constructFilter?: (filter: Filter) => any; + readonly constructSort?: (sort: Sort) => any; + readonly db: () => Promise; + readonly defaultPaginationLimit?: number; + readonly entityName: string; + readonly tableName: string; +} diff --git a/src/facade.ts b/src/facade.ts deleted file mode 100644 index 83417598c..000000000 --- a/src/facade.ts +++ /dev/null @@ -1,25 +0,0 @@ -import Facade from '@js-entity-repos/core/dist/Facade'; -import Config from './Config'; -import countEntities from './functions/countEntities'; -import createEntity from './functions/createEntity'; -import getEntities from './functions/getEntities'; -import getEntity from './functions/getEntity'; -import overwriteEntity from './functions/overwriteEntity'; -import patchEntity from './functions/patchEntity'; -import removeEntities from './functions/removeEntities'; -import removeEntity from './functions/removeEntity'; -import upsertEntity from './functions/upsertEntity'; - -export default (config: Config): Facade => { - return { - countEntities: countEntities(config), - createEntity: createEntity(config), - getEntities: getEntities(config), - getEntity: getEntity(config), - overwriteEntity: overwriteEntity(config), - patchEntity: patchEntity(config), - removeEntities: removeEntities(config), - removeEntity: removeEntity(config), - upsertEntity: upsertEntity(config), - }; -}; diff --git a/src/facade.test.ts b/src/factory.test.ts similarity index 64% rename from src/facade.test.ts rename to src/factory.test.ts index 9c3b49ae0..c29a9b5cb 100644 --- a/src/facade.test.ts +++ b/src/factory.test.ts @@ -1,8 +1,8 @@ import facadeTest from '@js-entity-repos/core/dist/tests'; -import { TestEntity, TestId } from '@js-entity-repos/core/dist/tests/utils/testEntity'; +import { TestEntity } from '@js-entity-repos/core/dist/tests/utils/testEntity'; import { config } from 'dotenv'; import 'mocha'; // tslint:disable-line:no-import-side-effect -import facade from './facade'; +import factory from './factory'; import connectToDb from './utils/connectToDb'; config(); @@ -21,8 +21,9 @@ const db = connectToDb({ const tableName = 'testentities'; before(async () => { - await Promise.resolve(db.schema.dropTableIfExists(tableName)); - await Promise.resolve(db.schema.createTableIfNotExists(tableName, async (table) => { + const schema = (await db()).schema; + await Promise.resolve(schema.dropTableIfExists(tableName)); + await Promise.resolve(schema.createTableIfNotExists(tableName, async (table) => { table.string('id').unique(); table.string('stringProp'); table.float('numberProp'); @@ -30,9 +31,7 @@ before(async () => { })); }); -facadeTest(facade({ - constructDocument: (id, patch) => ({ ...patch, ...id }), - constructEntity: (document) => document, +facadeTest(factory({ db, entityName: 'Test Entity', tableName, diff --git a/src/factory.ts b/src/factory.ts new file mode 100644 index 000000000..99d38f28d --- /dev/null +++ b/src/factory.ts @@ -0,0 +1,33 @@ +import Facade from '@js-entity-repos/core/dist/Facade'; +import Entity from '@js-entity-repos/core/dist/types/Entity'; +import FacadeConfig from './FacadeConfig'; +import FactoryConfig from './FactoryConfig'; +import countEntities from './functions/countEntities'; +import createEntity from './functions/createEntity'; +import getEntities from './functions/getEntities'; +import getEntity from './functions/getEntity'; +import patchEntity from './functions/patchEntity'; +import removeEntities from './functions/removeEntities'; +import removeEntity from './functions/removeEntity'; +import replaceEntity from './functions/replaceEntity'; + +export default (factoryConfig: FactoryConfig): Facade => { + const facadeConfig: FacadeConfig = { + constructDocument: (patch) => patch, + constructEntity: (document) => document, + constructFilter: (filter) => filter, + constructSort: (sort) => sort, + defaultPaginationLimit: 100, + ...factoryConfig, + }; + return { + countEntities: countEntities(facadeConfig), + createEntity: createEntity(facadeConfig), + getEntities: getEntities(facadeConfig), + getEntity: getEntity(facadeConfig), + patchEntity: patchEntity(facadeConfig), + removeEntities: removeEntities(facadeConfig), + removeEntity: removeEntity(facadeConfig), + replaceEntity: replaceEntity(facadeConfig), + }; +}; diff --git a/src/functions/countEntities.ts b/src/functions/countEntities.ts index 218025fef..85d32b69d 100644 --- a/src/functions/countEntities.ts +++ b/src/functions/countEntities.ts @@ -1,10 +1,11 @@ import CountEntities from '@js-entity-repos/core/dist/signatures/CountEntities'; -import Config from '../Config'; +import Entity from '@js-entity-repos/core/dist/types/Entity'; +import FacadeConfig from '../FacadeConfig'; import filterEntities from '../utils/filterEntities'; -export default (config: Config): CountEntities => { - return async ({ filter }) => { - const table = config.db.table(config.tableName); +export default (config: FacadeConfig): CountEntities => { + return async ({ filter = {} }) => { + const table = (await config.db()).table(config.tableName); const [result] = await Promise.resolve(filterEntities(table, filter).count()); return { count: result['count(*)'] }; }; diff --git a/src/functions/createEntity.ts b/src/functions/createEntity.ts index da0f455d6..1229319d7 100644 --- a/src/functions/createEntity.ts +++ b/src/functions/createEntity.ts @@ -1,13 +1,14 @@ import ConflictingEntityError from '@js-entity-repos/core/dist/errors/ConflictingEntityError'; import CreateEntity from '@js-entity-repos/core/dist/signatures/CreateEntity'; -import Config from '../Config'; +import Entity from '@js-entity-repos/core/dist/types/Entity'; +import FacadeConfig from '../FacadeConfig'; const conflictErrorCode = 1062; -export default (config: Config): CreateEntity => { +export default (config: FacadeConfig): CreateEntity => { return async ({ id, entity }) => { - const table = config.db.table(config.tableName); - const document = config.constructDocument(id, entity); + const table = (await config.db()).table(config.tableName); + const document = config.constructDocument({ ...entity as any, id }); try { await Promise.resolve(table.insert(document)); } catch (err) { diff --git a/src/functions/getEntities.ts b/src/functions/getEntities.ts index 41b75fbba..ab082ab0a 100644 --- a/src/functions/getEntities.ts +++ b/src/functions/getEntities.ts @@ -1,25 +1,35 @@ import GetEntities from '@js-entity-repos/core/dist/signatures/GetEntities'; +import Entity from '@js-entity-repos/core/dist/types/Entity'; +import Sort from '@js-entity-repos/core/dist/types/Sort'; import createCursorFromEntity from '@js-entity-repos/core/dist/utils/createCursorFromEntity'; import createPaginationFilter from '@js-entity-repos/core/dist/utils/createPaginationFilter'; import { first, last, mapValues } from 'lodash'; -import Config from '../Config'; +import FacadeConfig from '../FacadeConfig'; import filterEntities from '../utils/filterEntities'; const xor = (conditionA: boolean, conditionB: boolean) => { return (conditionA && !conditionB) || (!conditionA && conditionB); }; -export default (config: Config): GetEntities => { - return async ({ filter, sort, pagination }) => { - const table = config.db.table(config.tableName); +export default (config: FacadeConfig): GetEntities => { + const defaultPagination = { + cursor: undefined, + forward: true, + limit: config.defaultPaginationLimit, + }; + const defaultSort = { id: true } as Sort; + return async ({ filter = {}, sort = defaultSort, pagination = defaultPagination }) => { + const table = (await config.db()).table(config.tableName); const paginationFilter = createPaginationFilter(pagination, sort); const fullFilter = { $and: [filter, paginationFilter] }; - const knexSort = mapValues(sort, (sortValue: boolean) => { + const constructedFilter = config.constructFilter(fullFilter); + const constructedSort = config.constructSort(sort); + const knexSort = mapValues(constructedSort, (sortValue): string => { return !xor(pagination.forward, sortValue) ? 'asc' : 'desc'; }); - const filterQuery = filterEntities(table, fullFilter); + const filterQuery = filterEntities(table, constructedFilter); const sortQuery = Object.keys(knexSort).reduce((result, sortKey) => { return result.orderBy(sortKey, (knexSort as any)[sortKey]); }, filterQuery); diff --git a/src/functions/getEntity.ts b/src/functions/getEntity.ts index 50d65ad4e..a46f6fda7 100644 --- a/src/functions/getEntity.ts +++ b/src/functions/getEntity.ts @@ -1,12 +1,15 @@ import MissingEntityError from '@js-entity-repos/core/dist/errors/MissingEntityError'; import GetEntity from '@js-entity-repos/core/dist/signatures/GetEntity'; -import Config from '../Config'; +import Entity from '@js-entity-repos/core/dist/types/Entity'; +import FacadeConfig from '../FacadeConfig'; +import constructIdFilter from '../utils/constructIdFilter'; import filterEntities from '../utils/filterEntities'; -export default (config: Config): GetEntity => { - return async ({ id }) => { - const table = config.db.table(config.tableName); - const document = await Promise.resolve(filterEntities(table, id).first()); +export default (config: FacadeConfig): GetEntity => { + return async ({ id, filter = {} }) => { + const table = (await config.db()).table(config.tableName); + const constructedFilter = constructIdFilter({ id, filter, config }); + const document = await Promise.resolve(filterEntities(table, constructedFilter).first()); if (document === undefined || document === null) { throw new MissingEntityError(config.entityName, id); diff --git a/src/functions/overwriteEntity.ts b/src/functions/overwriteEntity.ts deleted file mode 100644 index b32f839a6..000000000 --- a/src/functions/overwriteEntity.ts +++ /dev/null @@ -1,12 +0,0 @@ -import OverwriteEntity from '@js-entity-repos/core/dist/signatures/OverwriteEntity'; -import Config from '../Config'; -import filterEntities from '../utils/filterEntities'; -import getEntity from './getEntity'; - -export default (config: Config): OverwriteEntity => { - return async ({ id, entity }) => { - const table = config.db.table(config.tableName); - await Promise.resolve(filterEntities(table, id).update(entity)); - return getEntity(config)({ id }); - }; -}; diff --git a/src/functions/patchEntity.ts b/src/functions/patchEntity.ts index f353ddc84..8f9f9ea14 100644 --- a/src/functions/patchEntity.ts +++ b/src/functions/patchEntity.ts @@ -1,12 +1,16 @@ import PatchEntity from '@js-entity-repos/core/dist/signatures/PatchEntity'; -import Config from '../Config'; +import Entity from '@js-entity-repos/core/dist/types/Entity'; +import FacadeConfig from '../FacadeConfig'; +import constructIdFilter from '../utils/constructIdFilter'; import filterEntities from '../utils/filterEntities'; import getEntity from './getEntity'; -export default (config: Config): PatchEntity => { - return async ({ id, patch }) => { - const table = config.db.table(config.tableName); - await Promise.resolve(filterEntities(table, id).update(patch)); - return getEntity(config)({ id }); +export default (config: FacadeConfig): PatchEntity => { + return async ({ id, patch, filter = {} }) => { + const table = (await config.db()).table(config.tableName); + const document = config.constructDocument({ ...patch as any, id }); + const constructedFilter = constructIdFilter({ id, filter, config }); + await Promise.resolve(filterEntities(table, constructedFilter).update(document)); + return getEntity(config)({ id, filter }); }; }; diff --git a/src/functions/removeEntities.ts b/src/functions/removeEntities.ts index d8e629a1f..a133a90c5 100644 --- a/src/functions/removeEntities.ts +++ b/src/functions/removeEntities.ts @@ -1,10 +1,12 @@ import RemoveEntities from '@js-entity-repos/core/dist/signatures/RemoveEntities'; -import Config from '../Config'; +import Entity from '@js-entity-repos/core/dist/types/Entity'; +import FacadeConfig from '../FacadeConfig'; import filterEntities from '../utils/filterEntities'; -export default (config: Config): RemoveEntities => { - return async ({ filter }) => { - const table = config.db.table(config.tableName); - await Promise.resolve(filterEntities(table, filter).delete()); +export default (config: FacadeConfig): RemoveEntities => { + return async ({ filter = {} }) => { + const table = (await config.db()).table(config.tableName); + const constructedFilter = config.constructFilter(filter); + await Promise.resolve(filterEntities(table, constructedFilter).delete()); }; }; diff --git a/src/functions/removeEntity.ts b/src/functions/removeEntity.ts index 36643ebdb..8f8d2dc7a 100644 --- a/src/functions/removeEntity.ts +++ b/src/functions/removeEntity.ts @@ -1,12 +1,15 @@ import MissingEntityError from '@js-entity-repos/core/dist/errors/MissingEntityError'; import RemoveEntity from '@js-entity-repos/core/dist/signatures/RemoveEntity'; -import Config from '../Config'; +import Entity from '@js-entity-repos/core/dist/types/Entity'; +import FacadeConfig from '../FacadeConfig'; +import constructIdFilter from '../utils/constructIdFilter'; import filterEntities from '../utils/filterEntities'; -export default (config: Config): RemoveEntity => { - return async ({ id }) => { - const table = config.db.table(config.tableName); - const count = await Promise.resolve(filterEntities(table, id).delete()); +export default (config: FacadeConfig): RemoveEntity => { + return async ({ id, filter = {} }) => { + const table = (await config.db()).table(config.tableName); + const constructedFilter = constructIdFilter({ id, filter, config }); + const count = await Promise.resolve(filterEntities(table, constructedFilter).delete()); if (count === 0) { throw new MissingEntityError(config.entityName, id); diff --git a/src/functions/replaceEntity.ts b/src/functions/replaceEntity.ts new file mode 100644 index 000000000..7ee9d723e --- /dev/null +++ b/src/functions/replaceEntity.ts @@ -0,0 +1,16 @@ +import ReplaceEntity from '@js-entity-repos/core/dist/signatures/ReplaceEntity'; +import Entity from '@js-entity-repos/core/dist/types/Entity'; +import FacadeConfig from '../FacadeConfig'; +import constructIdFilter from '../utils/constructIdFilter'; +import filterEntities from '../utils/filterEntities'; +import getEntity from './getEntity'; + +export default (config: FacadeConfig): ReplaceEntity => { + return async ({ id, entity, filter = {} }) => { + const table = (await config.db()).table(config.tableName); + const document = config.constructDocument({ ...entity as any, id }); + const constructedFilter = constructIdFilter({ id, filter, config }); + await Promise.resolve(filterEntities(table, constructedFilter).update(document)); + return getEntity(config)({ id, filter }); + }; +}; diff --git a/src/functions/upsertEntity.ts b/src/functions/upsertEntity.ts deleted file mode 100644 index 8218a22a8..000000000 --- a/src/functions/upsertEntity.ts +++ /dev/null @@ -1,19 +0,0 @@ -import ConflictingEntityError from '@js-entity-repos/core/dist/errors/ConflictingEntityError'; -import UpsertEntity from '@js-entity-repos/core/dist/signatures/UpsertEntity'; -import Config from '../Config'; -import createEntity from './createEntity'; -import overwriteEntity from './overwriteEntity'; - -export default (config: Config): UpsertEntity => { - return async ({ id, entity }) => { - try { - return await createEntity(config)({ id, entity }); - } catch (err) { - if (err instanceof ConflictingEntityError) { - return overwriteEntity(config)({ id, entity }); - } - /* istanbul ignore next */ - throw err; - } - }; -}; diff --git a/src/utils/connectToDb.ts b/src/utils/connectToDb.ts index 12d95f265..e8033d53d 100644 --- a/src/utils/connectToDb.ts +++ b/src/utils/connectToDb.ts @@ -1,5 +1,8 @@ import * as knex from 'knex'; +import { once } from 'lodash'; export default (connectionConfig: knex.Config) => { - return knex(connectionConfig); + return once(async () => { + return knex(connectionConfig); + }); }; diff --git a/src/utils/constructIdFilter.ts b/src/utils/constructIdFilter.ts new file mode 100644 index 000000000..c1d182200 --- /dev/null +++ b/src/utils/constructIdFilter.ts @@ -0,0 +1,16 @@ +import Entity from '@js-entity-repos/core/dist/types/Entity'; +import { Filter } from '@js-entity-repos/core/dist/types/Filter'; +import FacadeConfig from '../FacadeConfig'; + +export interface Opts { + readonly id: string; + readonly filter: Filter; + readonly config: FacadeConfig; +} + +export default ({ id, filter, config }: Opts) => { + const idFilter = { id } as Filter; + const fullFilter = { $and: [idFilter, filter] }; + const constructedFilter = config.constructFilter(fullFilter); + return constructedFilter; +}; diff --git a/src/utils/filterEntities.ts b/src/utils/filterEntities.ts index 7c9d534fb..9aec033d0 100644 --- a/src/utils/filterEntities.ts +++ b/src/utils/filterEntities.ts @@ -1,19 +1,20 @@ -// tslint:disable:no-use-before-declare +// tslint:disable:no-use-before-declare max-file-line-count +import Entity from '@js-entity-repos/core/dist/types/Entity'; import { - ConditionFilter, // tslint:disable-line:no-unused + ConditionFilter, EntityFilter, Filter, PropFilter, } from '@js-entity-repos/core/dist/types/Filter'; import { QueryBuilder } from 'knex'; -const addAndToQuery = (query: QueryBuilder, filters: Filter[]) => { +const addAndToQuery = (query: QueryBuilder, filters: Filter[]) => { return filters.reduce((result, filter) => { return constructFilter(result, filter); }, query); }; -const addOrToQuery = (query: QueryBuilder, filters: Filter[]) => { +const addOrToQuery = (query: QueryBuilder, filters: Filter[]) => { return filters.reduce((result, filter) => { return result.orWhere(function (this: QueryBuilder) { // tslint:disable-next-line:no-invalid-this no-this @@ -22,7 +23,7 @@ const addOrToQuery = (query: QueryBuilder, filters: Filter[]) => }, query); }; -const addNorToQuery = (query: QueryBuilder, filters: Filter[]) => { +const addNorToQuery = (query: QueryBuilder, filters: Filter[]) => { return query.whereNot(function (this: QueryBuilder) { // tslint:disable-next-line:no-invalid-this no-this addOrToQuery(this, filters); @@ -64,7 +65,7 @@ const constructPropFilter = ( return notQuery; }; -const constructEntityFilter = (query: QueryBuilder, filter: EntityFilter) => { +const constructEntityFilter = (query: QueryBuilder, filter: EntityFilter) => { return Object.keys(filter).reduce((result, prop) => { const filterValue = (filter as any)[prop]; if (!(filterValue instanceof Object)) { @@ -75,7 +76,10 @@ const constructEntityFilter = (query: QueryBuilder, filter: EntityFilter }, query); }; -const constructFilter = (query: QueryBuilder, filter: Filter): QueryBuilder => { +const constructConditionFilter = ( + query: QueryBuilder, + filter: ConditionFilter, +): QueryBuilder => { if (filter.$and !== undefined) { return addAndToQuery(query, filter.$and); } @@ -85,7 +89,15 @@ const constructFilter = (query: QueryBuilder, filter: Filter): Q if (filter.$nor !== undefined) { return addNorToQuery(query, filter.$nor); } - return constructEntityFilter(query, filter as EntityFilter); + return query; +}; + +const constructFilter = ( + query: QueryBuilder, + filter: Filter, +): QueryBuilder => { + const conditionQuery = constructConditionFilter(query, filter as any); + return constructEntityFilter(conditionQuery, filter as EntityFilter); }; export default constructFilter;