From 66b13918f827aa264cf3b140c5d050d209eb0b29 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Wed, 27 Oct 2021 05:22:08 +0300 Subject: [PATCH 01/40] feat(cache-improve): improved caching --- src/infra/BaseRepository.js | 79 ++++++++++++++---- src/infra/redis/RedisRepository.js | 80 ++++++++++++------- src/interfaces/index.js | 3 +- .../functions/infra/SequelizeModelStub.js | 64 +++++++++++++++ tests/infra/BaseRepository.test.js | 28 ++++++- 5 files changed, 201 insertions(+), 53 deletions(-) diff --git a/src/infra/BaseRepository.js b/src/infra/BaseRepository.js index 075e14f..156dcb9 100644 --- a/src/infra/BaseRepository.js +++ b/src/infra/BaseRepository.js @@ -43,7 +43,6 @@ class BaseRepository { * Provides configuration for BaseRepository. * * @param {Object} input The input object as injected in src/container.js - * @param {string} input.modelName The model name * @param {Object} input.model The db model * @param {Object} input.mapper The entity mapper * @param {string[]} [input.patchAllowedFields] The patch allowed fields array @@ -51,22 +50,25 @@ class BaseRepository { * @param {boolean} [input.cacheDisabled=false] Disable cahing */ init ({ - modelName, model, mapper, patchAllowedFields = undefined, - include = undefined, + include = [], cacheDisabled = false }) { - this.modelName = modelName + this.modelName = this._getModelName(model) this.model = model this.mapper = mapper this.patchAllowedFields = patchAllowedFields this.include = include this.cacheDisabled = cacheDisabled - const indexes = !cacheDisabled ? model._indexes : [] - this.redisRepository.init(modelName, indexes, include) + this.redisRepository.init({ + modelName: this.modelName, + indexes: this._getIndexes(model), + include: this._normalizeInclude(include), + references: this._getReferences(model) + }) } /** @@ -126,14 +128,14 @@ class BaseRepository { async findAll (where, options = {}) { this._validateFiler(where) - const results = await this.model.findAll({ + const rows = await this.model.findAll({ order: [['createdAt', 'DESC']], ...options, where, include: this.include, transaction: this._getTransaction() }) - return results.map(entry => entry.toJSON()) + return rows.map(row => this.mapper.toEntity(row.toJSON())) } /** @@ -169,7 +171,10 @@ class BaseRepository { transaction: this._getTransaction() }) const meta = this.paginate(currentPage, count, rows, pageSize) - return { data: rows.map(row => row.toJSON()), meta } + return { + data: rows.map(row => this.mapper.toEntity(row.toJSON())), + meta + } } /** @@ -188,7 +193,9 @@ class BaseRepository { this.mapper.toDatabase(entity), { transaction: this._getTransaction() } ) - return this.mapper.toEntity(dbEntry.toJSON()) + const json = dbEntry.toJSON() + await this._clearCache(json, true) + return this.mapper.toEntity(json) } /** @@ -230,7 +237,7 @@ class BaseRepository { throw this._getNotFoundError() } const json = result.toJSON() - await this._clearCache(json.id) + await this._clearCache(json) return this.mapper.toEntity(json) } catch (error) { switch (error.name) { @@ -275,7 +282,7 @@ class BaseRepository { throw this._getNotFoundError() } const json = result.toJSON() - await this._clearCache(json.id) + await this._clearCache(json) return this.mapper.toEntity(json) } catch (error) { switch (error.name) { @@ -290,6 +297,44 @@ class BaseRepository { } // Private + _getModelName (model) { + const modelName = model.options.name.singular + return modelName.charAt(0).toLowerCase() + modelName.slice(1) + } + + _getReferences (model) { + const models = Object.values(model.sequalize.models) + return Object.values(model.rawAttributes) + .filter(({ references }) => references && references.key === 'id') + .map(attr => { + const { model } = attr.references + const m = models.find(m => m.tableName === model) + return { + modelName: this._getModelName(m), + fieldName: attr.fieldName + } + }) + } + + _normalizeInclude (include) { + return include.map(({ model, as, include }) => ({ + modelName: this._getModelName(model), + as, + include: include && this._normalizeInclude(include) + })) + } + + _getIndexes (model) { + const models = Object.values(model.sequalize.models) + const entries = models.map(model => { + const modelName = this._getModelName(model) + const indexes = (model.options.indexes || []) + .filter(index => index.unique) + .map(index => index.fields) + return [modelName, indexes] + }) + return Object.fromEntries(entries) + } async _dbFindOne (where) { const result = await this.model.findOne({ @@ -303,11 +348,11 @@ class BaseRepository { } } - async _clearCache (id) { - if (!this.cacheDisabled) { - await this.redisRepository.delete(id) + async _clearCache (entity, skipReferenced = false) { + if (!this.cacheDisabled && !skipReferenced) { + await this.redisRepository.delete(entity) } - await this.redisRepository.clearRelated(id) + await this.redisRepository.clearRelated(entity, skipReferenced) } async _getPatchFilter (where) { @@ -383,7 +428,7 @@ class BaseRepository { } _getCapitalizedModelName () { - return this.modelName.charAt(0).toUpperCase() + this.modelName.slice(1) + return this.model.options.name.singular } _notFoundErrorMessage () { diff --git a/src/infra/redis/RedisRepository.js b/src/infra/redis/RedisRepository.js index f90af0e..e16d55a 100644 --- a/src/infra/redis/RedisRepository.js +++ b/src/infra/redis/RedisRepository.js @@ -1,5 +1,5 @@ import { get } from 'dot-get' -import isEqual from 'lodash/isEqual' +import { isEqual, unionWith } from 'lodash' import { REDIS_REPOSITORY_INITIALIZED, INVALID_FILTER, INVALID_FILTER_VALUE } from '../../errors' /** @@ -13,7 +13,12 @@ class RedisRepository { this.transactionProvider = transactionProvider } - init (modelName, indexes, include) { + init ({ + modelName, + indexes, + include, + references + }) { if (this._initialized) { // Error for developers only, can only occur if init was called more than once const error = new Error(REDIS_REPOSITORY_INITIALIZED.message) @@ -24,6 +29,7 @@ class RedisRepository { this.modelName = modelName this.include = include this.indexes = this._normalizeIndexes(indexes) + this.references = references } async findOneOrCreate (where, getObject) { @@ -57,43 +63,55 @@ class RedisRepository { async create (object) { const idKey = this._buildIdKey(this.modelName, object.id) await this._saveObject(idKey, object) - const cacheKeys = this._getObjectCacheKeys(this.modelName, this.indexes, object) + const cacheKeys = this._getObjectCacheKeys(this.modelName, object) await Promise.all(cacheKeys.map( key => this._saveObject(key, object.id) )) - await this._storeRelated(object) + await this._storeIncluded(object) return object } - delete (id) { - return this._delete(this.modelName, this.indexes, id) + delete ({ id }) { + return this._delete(this.modelName, id) } - async clearRelated (id) { - const key = this._buildRelationsKey(this.modelName, id) - const relations = await this.redisStorage.getList(key) - if (relations.length) { - await Promise.all( - relations.map(({ modelName, indexes, id }) => { - return this._delete(modelName, indexes, id) + async clearRelated (object, skipReferenced = false) { + const related = await this._getRelated(object, skipReferenced) + if (related.length) { + return Promise.all( + related.map(({ modelName, id }) => { + return this._delete(modelName, id) }) ) - return this._clearList(key, relations) } } + async _getRelated (object, skipReferenced) { + const relations = this.references.map(({ modelName, fieldName }) => ({ + modelName, + id: object[fieldName] + })) + if (skipReferenced) { + return relations + } + const key = this._buildRelationsKey(this.modelName, object.id) + const storedRelations = await this.redisStorage.getList(key) + await this._clearList(key, storedRelations) + return unionWith(relations, storedRelations, isEqual) + } + _normalizeIndexes (indexes) { - return indexes.filter(index => index.unique) - .filter(index => !index.fields.includes('id')) - .map(index => index.fields.sort()) + return indexes + .filter(fields => !fields.includes('id')) + .map(fields => fields.sort()) } - async _delete (modelName, indexes, id) { + async _delete (modelName, id) { const object = await this._getById(modelName, id) if (object) { const key = this._buildIdKey(modelName, id) await this._deleteObject(key, object) - const cacheKeys = this._getObjectCacheKeys(modelName, indexes, object) + const cacheKeys = this._getObjectCacheKeys(modelName, object) if (cacheKeys.length) { await Promise.all(cacheKeys.map( key => this._deleteObject(key, id) @@ -102,17 +120,16 @@ class RedisRepository { } } - async _storeRelated (entity) { - if (this.include && this.include.length) { + async _storeIncluded (entity) { + if (this.include.length) { const entityInfo = { id: entity.id, - modelName: this.modelName, - indexes: this.indexes + modelName: this.modelName } - const related = this._getRelated(entity, this.include) - if (related.length) { + const included = this._getIncluded(entity, this.include) + if (included.length) { await Promise.all( - related + included .map(({ modelName, id }) => this._buildRelationsKey(modelName, id)) .map(key => this._pushToList(key, entityInfo)) ) @@ -120,7 +137,7 @@ class RedisRepository { } } - _getRelated (entity, include) { + _getIncluded (entity, include) { return include.reduce((result, { modelName, as, include }) => { const related = entity[as] if (related) { @@ -131,7 +148,7 @@ class RedisRepository { id: object.id }) if (include) { - result.push(...this._getRelated(object, include)) + result.push(...this._getIncluded(object, include)) } }) } @@ -196,7 +213,8 @@ class RedisRepository { throw error } const sortedKeys = Object.keys(normalizedFilter).sort() - const valid = sortedKeys.includes('id') || this.indexes.find(key => isEqual(key, sortedKeys)) + const indexes = this.indexes[this.modelName] + const valid = sortedKeys.includes('id') || indexes.find(key => isEqual(key, sortedKeys)) if (!valid) { // Error for developers only, can only occur if the indexes configuration is incorrect const error = new Error(`${INVALID_FILTER.message}: "${JSON.stringify(sortedKeys)}"`) @@ -243,8 +261,8 @@ class RedisRepository { } } - _getObjectCacheKeys (modelName, indexes, object) { - return indexes.map(index => { + _getObjectCacheKeys (modelName, object) { + return this.indexes[modelName].map(index => { const filter = index.reduce((res, field) => ({ ...res, [field]: get(object, field) diff --git a/src/interfaces/index.js b/src/interfaces/index.js index 51aa101..6cff84b 100644 --- a/src/interfaces/index.js +++ b/src/interfaces/index.js @@ -154,8 +154,7 @@ export const deviceMiddleware = (req, res, next) => { export const errorHandler = (err, req, res, next) => { res.status(Status.INTERNAL_SERVER_ERROR).json({ type: 'InternalServerError', - message: 'The server failed to handle this request', - errors: err.errors + message: 'The server failed to handle this request' }) } /** diff --git a/tests/fixtures/functions/infra/SequelizeModelStub.js b/tests/fixtures/functions/infra/SequelizeModelStub.js index a261ca2..99c7aa5 100644 --- a/tests/fixtures/functions/infra/SequelizeModelStub.js +++ b/tests/fixtures/functions/infra/SequelizeModelStub.js @@ -1,4 +1,68 @@ export default { + tableName: 'ModelName', + options: { + name: { + singular: 'ModelName' + } + }, + rawAttributes: { + id: { + allowNull: false, + primaryKey: true, + Model: { + options: { + name: { + singular: 'ModelName' + } + } + }, + fieldName: 'id', + _modelAttribute: true, + field: 'id' + }, + otherId: { + allowNull: false, + Model: { + options: { + name: { + singular: 'ModelName' + } + } + }, + fieldName: 'otherId', + references: { model: 'Other', key: 'id' }, + _modelAttribute: true, + field: 'otherId' + } + }, + sequalize: { + models: [ + { + tableName: 'ModelName', + options: { + name: { + singular: 'ModelName' + }, + indexes: [ + { unique: false }, + { unique: true, fields: ['a', 'b'] }, + { unique: true, fields: ['c', 'd'] } + ] + } + }, + { + tableName: 'Other', + options: { + name: { + singular: 'Other' + }, + indexes: [ + { unique: false } + ] + } + } + ] + }, findOne () { return true }, diff --git a/tests/infra/BaseRepository.test.js b/tests/infra/BaseRepository.test.js index 7ab91e4..65b0eff 100644 --- a/tests/infra/BaseRepository.test.js +++ b/tests/infra/BaseRepository.test.js @@ -50,7 +50,6 @@ describe('BaseRepository', function () { describe('init', function () { const opts = { - modelName: 'modelName', model: SequelizeModelStub, mapper: EntityMapperStub, patchAllowedFields: ['field', 'field2'], @@ -64,10 +63,33 @@ describe('BaseRepository', function () { cacheDisabled: false } it('should init BaseRepository', async function () { + sinon.spy(RedisRepositoryStub, 'init') baseRepository.init(opts) Object.entries(opts).forEach(([key, value]) => { expect(baseRepository[key]).to.deep.equal(value) }) + expect(baseRepository.modelName).to.deep.equal('modelName') + RedisRepositoryStub.init.should.have.been.calledWith({ + modelName: 'modelName', + indexes: { + modelName: [ + ['a', 'b'], + ['c', 'd'] + ], + other: [] + }, + references: [ + { modelName: 'other', fieldName: 'otherId' } + ], + include: [ + { + modelName: 'modelName', + as: 'realted', + include: undefined + } + ] + }) + RedisRepositoryStub.init.restore() }) }) @@ -503,7 +525,7 @@ describe('BaseRepository', function () { EntityMapperStub.toEntity.should.have.been.calledOnce EntityMapperStub.toEntity.should.have.been.calledWith(obj) RedisRepositoryStub.delete.should.have.been.calledOnce - expect(RedisRepositoryStub.delete.getCall(0).args[0]).to.deep.equal(obj.id) + expect(RedisRepositoryStub.delete.getCall(0).args[0]).to.deep.equal(obj) expect(res).to.deep.equal(domainEntity) baseRepository._filterPatchFields.restore() @@ -647,7 +669,7 @@ describe('BaseRepository', function () { EntityMapperStub.toEntity.should.have.been.calledOnce EntityMapperStub.toEntity.should.have.been.calledWith(obj) RedisRepositoryStub.delete.should.have.been.calledOnce - RedisRepositoryStub.delete.should.have.been.calledWith(obj.id) + RedisRepositoryStub.delete.should.have.been.calledWith(obj) expect(res).to.deep.equal(domainEntity) baseRepository._getPatchFilter.restore() From 33344cd8399fc985f683915f8a64458369a390ac Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Wed, 27 Oct 2021 16:55:22 +0300 Subject: [PATCH 02/40] feat(cache-improve): improved caching --- src/infra/redis/RedisRepository.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/infra/redis/RedisRepository.js b/src/infra/redis/RedisRepository.js index e16d55a..9eb39bb 100644 --- a/src/infra/redis/RedisRepository.js +++ b/src/infra/redis/RedisRepository.js @@ -90,7 +90,7 @@ class RedisRepository { const relations = this.references.map(({ modelName, fieldName }) => ({ modelName, id: object[fieldName] - })) + })).filter(r => r.id) if (skipReferenced) { return relations } From 833e35784e83dea8e59758c65926e4f50e9e4f30 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Fri, 29 Oct 2021 06:08:41 +0300 Subject: [PATCH 03/40] feat(cache-improve): improved caching --- src/infra/BaseRepository.js | 9 ++-- src/infra/redis/RedisRepository.js | 53 +++++++++++-------- src/infra/transaction/TransactionProvider.js | 17 +++--- .../infra/redis/RedisRepositoryStub.js | 4 +- tests/infra/BaseRepository.test.js | 41 +++++++------- 5 files changed, 69 insertions(+), 55 deletions(-) diff --git a/src/infra/BaseRepository.js b/src/infra/BaseRepository.js index 156dcb9..9a6673f 100644 --- a/src/infra/BaseRepository.js +++ b/src/infra/BaseRepository.js @@ -194,7 +194,7 @@ class BaseRepository { { transaction: this._getTransaction() } ) const json = dbEntry.toJSON() - await this._clearCache(json, true) + await this.redisRepository.clearReferenced(json) return this.mapper.toEntity(json) } @@ -348,11 +348,8 @@ class BaseRepository { } } - async _clearCache (entity, skipReferenced = false) { - if (!this.cacheDisabled && !skipReferenced) { - await this.redisRepository.delete(entity) - } - await this.redisRepository.clearRelated(entity, skipReferenced) + _clearCache (entity) { + return this.redisRepository.clear(entity, this.cacheDisabled) } async _getPatchFilter (where) { diff --git a/src/infra/redis/RedisRepository.js b/src/infra/redis/RedisRepository.js index 9eb39bb..063fa55 100644 --- a/src/infra/redis/RedisRepository.js +++ b/src/infra/redis/RedisRepository.js @@ -1,5 +1,5 @@ import { get } from 'dot-get' -import { isEqual, unionWith } from 'lodash' +import isEqual from 'lodash/isEqual' import { REDIS_REPOSITORY_INITIALIZED, INVALID_FILTER, INVALID_FILTER_VALUE } from '../../errors' /** @@ -71,42 +71,49 @@ class RedisRepository { return object } - delete ({ id }) { - return this._delete(this.modelName, id) + async clearReferenced (object) { + const references = this.references.map(({ modelName, fieldName }) => ({ + modelName, + id: object[fieldName] + })).filter(r => r.id) + if (references.length) { + await Promise.all( + references.map(({ modelName, id }) => this._clear(modelName, id)) + ) + } + } + + clear ({ id }, relationsOnly) { + return this._clear(this.modelName, id, relationsOnly) } - async clearRelated (object, skipReferenced = false) { - const related = await this._getRelated(object, skipReferenced) + _clear (modelName, id, relationsOnly) { + return Promise.all([ + !relationsOnly ? this._clearObject(this.modelName, id) : null, + this._clearRelated(modelName, id) + ].filter(Boolean)) + } + + async _clearRelated (modelName, id) { + const key = this._buildRelationsKey(modelName, id) + const related = await this.redisStorage.getList(key) + await this._clearList(key, related) if (related.length) { - return Promise.all( + await Promise.all( related.map(({ modelName, id }) => { - return this._delete(modelName, id) + return this._deleteObject(modelName, id) }) ) } } - async _getRelated (object, skipReferenced) { - const relations = this.references.map(({ modelName, fieldName }) => ({ - modelName, - id: object[fieldName] - })).filter(r => r.id) - if (skipReferenced) { - return relations - } - const key = this._buildRelationsKey(this.modelName, object.id) - const storedRelations = await this.redisStorage.getList(key) - await this._clearList(key, storedRelations) - return unionWith(relations, storedRelations, isEqual) - } - _normalizeIndexes (indexes) { return indexes .filter(fields => !fields.includes('id')) .map(fields => fields.sort()) } - async _delete (modelName, id) { + async _clearObject (modelName, id) { const object = await this._getById(modelName, id) if (object) { const key = this._buildIdKey(modelName, id) @@ -171,7 +178,7 @@ class RedisRepository { async _pushToList (key, object) { await this.redisStorage.listPush(key, object) this.transactionProvider.addRedisRollback( - async () => this.redisStorage.listRemove(key, object) + () => this.redisStorage.listRemove(key, object) ) } diff --git a/src/infra/transaction/TransactionProvider.js b/src/infra/transaction/TransactionProvider.js index 67291b8..9d9bdf3 100644 --- a/src/infra/transaction/TransactionProvider.js +++ b/src/infra/transaction/TransactionProvider.js @@ -10,18 +10,23 @@ class TransactionProvider { } async useTransaction (action) { + // Check for cases when useTransaction is called inside useTransaction, + // so only outer transaction wrapping should commit changes + if (this.current) { + return action() + } try { - await this.transaction() + await this._transaction() const response = await action() - await this.commit() + await this._commit() return response } catch (error) { - await this.rollback() + await this._rollback() throw error } } - async transaction () { + async _transaction () { if (!this.current) { const transaction = new this.Transaction(this.database) this.current = await transaction.begin() @@ -29,12 +34,12 @@ class TransactionProvider { return this.current } - async commit () { + async _commit () { await this.current.commit() this.current = undefined } - async rollback () { + async _rollback () { await this.current.rollback() this.current = undefined } diff --git a/tests/fixtures/functions/infra/redis/RedisRepositoryStub.js b/tests/fixtures/functions/infra/redis/RedisRepositoryStub.js index 44ff446..7803720 100644 --- a/tests/fixtures/functions/infra/redis/RedisRepositoryStub.js +++ b/tests/fixtures/functions/infra/redis/RedisRepositoryStub.js @@ -14,10 +14,10 @@ export default { create (obj) { return obj }, - delete () { + clear () { return true }, - clearRelated () { + clearReferenced () { return true } } diff --git a/tests/infra/BaseRepository.test.js b/tests/infra/BaseRepository.test.js index 65b0eff..6970e89 100644 --- a/tests/infra/BaseRepository.test.js +++ b/tests/infra/BaseRepository.test.js @@ -381,6 +381,7 @@ describe('BaseRepository', function () { sinon.spy(entity, 'validate') sinon.spy(baseRepository, '_getValidationError') + sinon.spy(RedisRepositoryStub, 'clearReferenced') sinon.stub(SequelizeModelStub, 'create').callsFake(() => dbEntry) sinon.stub(EntityMapperStub, 'toDatabase').callsFake(() => obj) sinon.stub(EntityMapperStub, 'toEntity').callsFake(() => entity) @@ -398,6 +399,8 @@ describe('BaseRepository', function () { EntityMapperStub.toDatabase.should.have.been.calledOnce EntityMapperStub.toDatabase.should.have.been.calledWith(entity) expect(SequelizeModelStub.create.getCall(0).args[0]).to.deep.equal(obj) + RedisRepositoryStub.clearReferenced.should.have.been.calledOnce + RedisRepositoryStub.clearReferenced.should.have.been.calledWith(obj) EntityMapperStub.toEntity.should.have.been.calledOnce EntityMapperStub.toEntity.should.have.been.calledWith(obj) @@ -405,6 +408,7 @@ describe('BaseRepository', function () { entity.validate.restore() baseRepository._getValidationError.restore() + RedisRepositoryStub.clearReferenced.restore() SequelizeModelStub.create.restore() EntityMapperStub.toDatabase.restore() EntityMapperStub.toEntity.restore() @@ -506,7 +510,7 @@ describe('BaseRepository', function () { sinon.stub(SequelizeModelStub, 'update').callsFake(() => [1, dbEntry]) sinon.spy(baseRepository, '_getNotFoundError') sinon.stub(EntityMapperStub, 'toEntity').callsFake(() => domainEntity) - sinon.spy(RedisRepositoryStub, 'delete') + sinon.spy(RedisRepositoryStub, 'clear') baseRepository.init({ modelName: 'modelName', @@ -524,8 +528,8 @@ describe('BaseRepository', function () { baseRepository._getNotFoundError.should.have.not.been.called EntityMapperStub.toEntity.should.have.been.calledOnce EntityMapperStub.toEntity.should.have.been.calledWith(obj) - RedisRepositoryStub.delete.should.have.been.calledOnce - expect(RedisRepositoryStub.delete.getCall(0).args[0]).to.deep.equal(obj) + RedisRepositoryStub.clear.should.have.been.calledOnce + expect(RedisRepositoryStub.clear.getCall(0).args[0]).to.deep.equal(obj) expect(res).to.deep.equal(domainEntity) baseRepository._filterPatchFields.restore() @@ -533,7 +537,7 @@ describe('BaseRepository', function () { SequelizeModelStub.update.restore() baseRepository._getNotFoundError.restore() EntityMapperStub.toEntity.restore() - RedisRepositoryStub.delete.restore() + RedisRepositoryStub.clear.restore() }) it('should patch entity (cacheDisabled=true)', async function () { @@ -542,7 +546,7 @@ describe('BaseRepository', function () { sinon.stub(SequelizeModelStub, 'update').callsFake(() => [1, dbEntry]) sinon.spy(baseRepository, '_getNotFoundError') sinon.stub(EntityMapperStub, 'toEntity').callsFake(() => domainEntity) - sinon.spy(RedisRepositoryStub, 'delete') + sinon.spy(RedisRepositoryStub, 'clear') baseRepository.init({ modelName: 'modelName', @@ -568,7 +572,7 @@ describe('BaseRepository', function () { SequelizeModelStub.update.restore() baseRepository._getNotFoundError.restore() EntityMapperStub.toEntity.restore() - RedisRepositoryStub.delete.restore() + RedisRepositoryStub.clear.restore() }) it('should throw NotFound on patch entity', async function () { @@ -577,7 +581,7 @@ describe('BaseRepository', function () { sinon.stub(SequelizeModelStub, 'update').callsFake(() => [0]) sinon.spy(baseRepository, '_getNotFoundError') sinon.spy(EntityMapperStub, 'toEntity') - sinon.spy(RedisRepositoryStub, 'delete') + sinon.spy(RedisRepositoryStub, 'clear') baseRepository.init({ modelName: 'modelName', @@ -600,7 +604,7 @@ describe('BaseRepository', function () { expect(SequelizeModelStub.update.getCall(0).args[1].where).to.deep.equal(where) baseRepository._getNotFoundError.should.have.been.calledOnce EntityMapperStub.toEntity.should.have.not.been.called - RedisRepositoryStub.delete.should.have.not.been.called + RedisRepositoryStub.clear.should.have.not.been.called expect(error.message).to.equal('NotFoundError') baseRepository._filterPatchFields.restore() @@ -608,7 +612,7 @@ describe('BaseRepository', function () { SequelizeModelStub.update.restore() baseRepository._getNotFoundError.restore() EntityMapperStub.toEntity.restore() - RedisRepositoryStub.delete.restore() + RedisRepositoryStub.clear.restore() }) }) @@ -651,7 +655,7 @@ describe('BaseRepository', function () { sinon.stub(SequelizeModelStub, 'destroy').callsFake(() => [1, dbEntry]) sinon.spy(baseRepository, '_getNotFoundError') sinon.stub(EntityMapperStub, 'toEntity').callsFake(() => domainEntity) - sinon.spy(RedisRepositoryStub, 'delete') + sinon.spy(RedisRepositoryStub, 'clear') baseRepository.init({ modelName: 'modelName', @@ -668,15 +672,15 @@ describe('BaseRepository', function () { baseRepository._getNotFoundError.should.have.not.been.called EntityMapperStub.toEntity.should.have.been.calledOnce EntityMapperStub.toEntity.should.have.been.calledWith(obj) - RedisRepositoryStub.delete.should.have.been.calledOnce - RedisRepositoryStub.delete.should.have.been.calledWith(obj) + RedisRepositoryStub.clear.should.have.been.calledOnce + RedisRepositoryStub.clear.should.have.been.calledWith(obj) expect(res).to.deep.equal(domainEntity) baseRepository._getPatchFilter.restore() SequelizeModelStub.destroy.restore() baseRepository._getNotFoundError.restore() EntityMapperStub.toEntity.restore() - RedisRepositoryStub.delete.restore() + RedisRepositoryStub.clear.restore() }) it('should delete entity (cacheDisabled=true)', async function () { @@ -684,7 +688,7 @@ describe('BaseRepository', function () { sinon.stub(SequelizeModelStub, 'destroy').callsFake(() => [1, dbEntry]) sinon.spy(baseRepository, '_getNotFoundError') sinon.stub(EntityMapperStub, 'toEntity').callsFake(() => domainEntity) - sinon.spy(RedisRepositoryStub, 'delete') + sinon.spy(RedisRepositoryStub, 'clear') baseRepository.init({ modelName: 'modelName', @@ -699,6 +703,7 @@ describe('BaseRepository', function () { baseRepository._getPatchFilter.should.have.been.calledWith(where) SequelizeModelStub.destroy.should.have.been.calledOnce expect(SequelizeModelStub.destroy.getCall(0).args[0].where).to.deep.equal(where) + RedisRepositoryStub.clear.should.have.been.calledWith(obj, true) baseRepository._getNotFoundError.should.have.not.been.called EntityMapperStub.toEntity.should.have.been.calledOnce EntityMapperStub.toEntity.should.have.been.calledWith(obj) @@ -708,7 +713,7 @@ describe('BaseRepository', function () { SequelizeModelStub.destroy.restore() baseRepository._getNotFoundError.restore() EntityMapperStub.toEntity.restore() - RedisRepositoryStub.delete.restore() + RedisRepositoryStub.clear.restore() }) it('should throw NotFound on patch entity', async function () { @@ -716,7 +721,7 @@ describe('BaseRepository', function () { sinon.stub(SequelizeModelStub, 'destroy').callsFake(() => [0]) sinon.spy(baseRepository, '_getNotFoundError') sinon.spy(EntityMapperStub, 'toEntity') - sinon.spy(RedisRepositoryStub, 'delete') + sinon.spy(RedisRepositoryStub, 'clear') baseRepository.init({ modelName: 'modelName', @@ -737,14 +742,14 @@ describe('BaseRepository', function () { expect(SequelizeModelStub.destroy.getCall(0).args[0].where).to.deep.equal(where) baseRepository._getNotFoundError.should.have.been.calledOnce EntityMapperStub.toEntity.should.have.not.been.called - RedisRepositoryStub.delete.should.have.not.been.called + RedisRepositoryStub.clear.should.have.not.been.called expect(error.message).to.deep.equal('NotFoundError') baseRepository._getPatchFilter.restore() SequelizeModelStub.destroy.restore() baseRepository._getNotFoundError.restore() EntityMapperStub.toEntity.restore() - RedisRepositoryStub.delete.restore() + RedisRepositoryStub.clear.restore() }) }) From da43fecbaadac4b52cdedef2b1187e9d068ce99b Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Fri, 29 Oct 2021 06:56:42 +0300 Subject: [PATCH 04/40] feat(cache-improve): improved caching --- package.json | 2 ++ src/infra/index.js | 33 ++++++++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 6d52f0c..7f71678 100644 --- a/package.json +++ b/package.json @@ -55,10 +55,12 @@ "http-status": "^1.4.2", "https": "^1.0.0", "lodash": "^4.17.20", + "paginate-info": "^1.0.4", "structure": "^2.0.1", "winston": "^3.2.1" }, "peerDependencies": { + "awilix": "^5.0.1", "awilix-express": "^5.0.0" }, "directories": { diff --git a/src/infra/index.js b/src/infra/index.js index d46ab60..77ca607 100644 --- a/src/infra/index.js +++ b/src/infra/index.js @@ -1,5 +1,32 @@ +import { asClass, asFunction, asValue } from 'awilix' +import { calculateLimitAndOffset, paginate } from 'paginate-info' +import { Transaction, TransactionProvider } from './transaction' +import { RedisRepository, RedisStorage, redis } from './redis' + +export { Transaction, TransactionProvider } +export { RedisRepository, RedisStorage, redis } +export { default as BaseRepository } from './BaseRepository' export { default as LoggerStreamAdapter } from './LoggerStreamAdapter' export { default as ModelLoader } from './ModelLoader' -export { default as BaseRepository } from './BaseRepository' -export * from './transaction' -export * from './redis' + +export function register (container, repositories) { + container.register({ + calculateLimitAndOffset: asValue(calculateLimitAndOffset), + paginate: asValue(paginate), + redis: asFunction(redis).singleton(), + redisStorage: asClass(RedisStorage).singleton(), + redisRepository: asClass(RedisRepository), + Transaction: asValue(Transaction), + transactionProvider: asClass(TransactionProvider).scoped() + }) + container.register(Object.fromEntries( + Object.entries(repositories).map(([name, repository]) => [ + _lovercaseName(name), + asClass(repository).scoped() + ]) + )) +} + +function _lovercaseName (name) { + return name.charAt(0).toLowerCase() + name.slice(1) +} From d2b6c025c10977c06a643a6664926fcccf62326a Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Fri, 29 Oct 2021 09:08:47 +0300 Subject: [PATCH 05/40] feat(cache-improve): improved caching --- tests/fixtures/functions/infra/SequelizeModelStub.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/fixtures/functions/infra/SequelizeModelStub.js b/tests/fixtures/functions/infra/SequelizeModelStub.js index 99c7aa5..112590b 100644 --- a/tests/fixtures/functions/infra/SequelizeModelStub.js +++ b/tests/fixtures/functions/infra/SequelizeModelStub.js @@ -36,8 +36,8 @@ export default { } }, sequalize: { - models: [ - { + models: { + ModelName: { tableName: 'ModelName', options: { name: { @@ -50,7 +50,7 @@ export default { ] } }, - { + Other: { tableName: 'Other', options: { name: { @@ -61,7 +61,7 @@ export default { ] } } - ] + } }, findOne () { return true From 92a70e6c9a24241ccadfca9479f01fbca2150a56 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Wed, 3 Nov 2021 16:59:04 +0200 Subject: [PATCH 06/40] feat(cache-improve): improved caching --- src/infra/BaseRepository.js | 72 ++++++++++++++++++++++++++++++------- src/infra/index.js | 31 ++++++++-------- 2 files changed, 76 insertions(+), 27 deletions(-) diff --git a/src/infra/BaseRepository.js b/src/infra/BaseRepository.js index 7671952..50bac1d 100644 --- a/src/infra/BaseRepository.js +++ b/src/infra/BaseRepository.js @@ -30,14 +30,15 @@ class BaseRepository { redisRepository, calculateLimitAndOffset, paginate, - config: { logmsg }, + config, standardError }) { this.transactionProvider = transactionProvider this.redisRepository = redisRepository this.calculateLimitAndOffset = calculateLimitAndOffset this.paginate = paginate - this.logmsg = logmsg + this.config = config + this.logmsg = config.logmsg this.standardError = standardError } @@ -55,7 +56,7 @@ class BaseRepository { model, mapper, patchAllowedFields = undefined, - include = [], + include = undefined, cacheDisabled = false }) { this.modelName = this._getModelName(model) @@ -117,20 +118,59 @@ class BaseRepository { } } + /** + * Сount entities by filter + * + * @param {Object} where filter + * @param {Object} [options] additional sequelize options + * @returns {Promise} number of entities + */ + count (where, options) { + return this.model.count({ + ...options, + where, + include: this.include, + transaction: this._getTransaction() + }) + } + + /** + * Returns latest entry + * + * @param {Object} [where] filter + * @param {Object} [options] additional sequelize options + * @param {String} [options.orderBy] order field + * @returns {Promise} entity + * @throws {module:interface.standardError} + */ + async findLatest (where = undefined, { rejectOnEmpty = true, ...opts } = {}) { + const [result] = await this.findAll(where, { + limit: 1, + ...opts + }) + if (result) { + return result + } + if (rejectOnEmpty) { + throw this._getNotFoundError() + } + } + /** * Finds entities by filter * * @param {Object} where filter * @param {Object} [options] additional sequelize options + * @param {String} [options.orderBy] order field * @returns {Promise} entities * @throws {module:interface.standardError} */ - async findAll (where, options = {}) { + async findAll (where, { orderBy = 'createdAt', ...opts } = {}) { this._validateFilter(where) const rows = await this.model.findAll({ - order: [['createdAt', 'DESC']], - ...options, + order: [[orderBy, 'DESC']], + ...opts, where, include: this.include, transaction: this._getTransaction() @@ -150,18 +190,19 @@ class BaseRepository { * @param {number} currentPage current page number * @param {number} pageSize page size * @param {Object} [options] additional sequelize options + * @param {String} [options.orderBy] order field * @returns {Promise<{ data: Object[], meta: Meta>} entities * @throws {module:interface.standardError} */ - async findAndCountAll (where, currentPage, pageSize, options = {}) { + async findAndCountAll (where, currentPage, pageSize, { orderBy = 'createdAt', ...opts } = {}) { this._validateFilter(where) this._validatePaginateParams(currentPage, pageSize) const { limit, offset } = this.calculateLimitAndOffset(currentPage, pageSize) const { rows, count } = await this.model.findAndCountAll({ - order: [['createdAt', 'DESC']], - ...options, + order: [[orderBy, 'DESC']], + ...opts, limit, offset, distinct: true, @@ -202,11 +243,12 @@ class BaseRepository { * * @param {string} id entity uuid * @param {Object} updateFields the fields to be updated + * @param {boolean} [filterFields=true] should filter updateFields * @returns {Promise} updated domain entity * @throws {module:interface.standardError} */ - async patchById (id, updateFields) { - return this.patch({ id }, updateFields) + async patchById (id, updateFields, filterFields = true) { + return this.patch({ id }, updateFields, filterFields) } /** @@ -214,13 +256,14 @@ class BaseRepository { * * @param {Object} where filter * @param {Object} updateFields the fields to be updated + * @param {boolean} [filterFields=true] should filter updateFields * @returns {Promise} updated domain entity * @throws {module:interface.standardError} */ - async patch (where, updateFields) { + async patch (where, updateFields, filterFields = true) { this._validateFilter(where) - const filteredFields = this._filterPatchFields(updateFields) + const filteredFields = filterFields ? this._filterPatchFields(updateFields) : updateFields try { const filter = await this._getPatchFilter(where) const [, result] = await this.model.update(filteredFields, { @@ -313,6 +356,9 @@ class BaseRepository { } _normalizeInclude (include) { + if (!include) { + return [] + } return include.map(({ model, as, include }) => ({ modelName: this._getModelName(model), as, diff --git a/src/infra/index.js b/src/infra/index.js index 77ca607..902b7d2 100644 --- a/src/infra/index.js +++ b/src/infra/index.js @@ -3,13 +3,7 @@ import { calculateLimitAndOffset, paginate } from 'paginate-info' import { Transaction, TransactionProvider } from './transaction' import { RedisRepository, RedisStorage, redis } from './redis' -export { Transaction, TransactionProvider } -export { RedisRepository, RedisStorage, redis } -export { default as BaseRepository } from './BaseRepository' -export { default as LoggerStreamAdapter } from './LoggerStreamAdapter' -export { default as ModelLoader } from './ModelLoader' - -export function register (container, repositories) { +function register (container, repositories) { container.register({ calculateLimitAndOffset: asValue(calculateLimitAndOffset), paginate: asValue(paginate), @@ -19,14 +13,23 @@ export function register (container, repositories) { Transaction: asValue(Transaction), transactionProvider: asClass(TransactionProvider).scoped() }) - container.register(Object.fromEntries( - Object.entries(repositories).map(([name, repository]) => [ - _lovercaseName(name), - asClass(repository).scoped() - ]) - )) + container.register( + Object.fromEntries( + Object.entries(repositories).map(([name, repository]) => [ + lowerСaseName(name), + asClass(repository).scoped() + ]) + ) + ) } -function _lovercaseName (name) { +function lowerСaseName (name) { return name.charAt(0).toLowerCase() + name.slice(1) } + +export { register } +export { Transaction, TransactionProvider } +export { RedisRepository, RedisStorage, redis } +export { default as BaseRepository } from './BaseRepository' +export { default as LoggerStreamAdapter } from './LoggerStreamAdapter' +export { default as ModelLoader } from './ModelLoader' From d1bca176e9d3c43735b2d1653b76f08632c62398 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Wed, 2 Feb 2022 14:21:50 +0200 Subject: [PATCH 07/40] 2.0.0-beta.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d32bcab..2c35d06 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@charge-tech/chargejs", - "version": "0.1.0", + "version": "2.0.0-beta.0", "description": "The Charge Core JS implementation.", "main": "src/index.js", "engines": { From 3499356f80d8625a6e9bb3790e36061f88d600dc Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Wed, 2 Feb 2022 15:40:51 +0200 Subject: [PATCH 08/40] feat(cache-improve): improved caching --- src/infra/BaseRepository.js | 4 ++-- tests/fixtures/functions/infra/SequelizeModelStub.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/infra/BaseRepository.js b/src/infra/BaseRepository.js index 50bac1d..96cb11f 100644 --- a/src/infra/BaseRepository.js +++ b/src/infra/BaseRepository.js @@ -342,7 +342,7 @@ class BaseRepository { } _getReferences (model) { - const models = Object.values(model.sequalize.models) + const models = Object.values(model.sequelize.models) return Object.values(model.rawAttributes) .filter(({ references }) => references && references.key === 'id') .map(attr => { @@ -367,7 +367,7 @@ class BaseRepository { } _getIndexes (model) { - const models = Object.values(model.sequalize.models) + const models = Object.values(model.sequelize.models) const entries = models.map(model => { const modelName = this._getModelName(model) const indexes = (model.options.indexes || []) diff --git a/tests/fixtures/functions/infra/SequelizeModelStub.js b/tests/fixtures/functions/infra/SequelizeModelStub.js index 112590b..33d3595 100644 --- a/tests/fixtures/functions/infra/SequelizeModelStub.js +++ b/tests/fixtures/functions/infra/SequelizeModelStub.js @@ -35,7 +35,7 @@ export default { field: 'otherId' } }, - sequalize: { + sequelize: { models: { ModelName: { tableName: 'ModelName', From bdf34a37863fccb14db3a7e98b92f1cc7703e9bd Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Wed, 2 Feb 2022 15:41:05 +0200 Subject: [PATCH 09/40] 2.0.0-beta.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2c35d06..0b98d3d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@charge-tech/chargejs", - "version": "2.0.0-beta.0", + "version": "2.0.0-beta.1", "description": "The Charge Core JS implementation.", "main": "src/index.js", "engines": { From 2f7d4acf9eae339a38cb17a7132d6f627631a975 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Wed, 2 Feb 2022 15:55:07 +0200 Subject: [PATCH 10/40] feat(cache-improve): improved caching --- src/infra/redis/RedisRepository.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/infra/redis/RedisRepository.js b/src/infra/redis/RedisRepository.js index 063fa55..21e9bcf 100644 --- a/src/infra/redis/RedisRepository.js +++ b/src/infra/redis/RedisRepository.js @@ -1,3 +1,4 @@ +import ret from 'bluebird/js/release/util' import { get } from 'dot-get' import isEqual from 'lodash/isEqual' import { REDIS_REPOSITORY_INITIALIZED, INVALID_FILTER, INVALID_FILTER_VALUE } from '../../errors' @@ -108,9 +109,12 @@ class RedisRepository { } _normalizeIndexes (indexes) { - return indexes - .filter(fields => !fields.includes('id')) - .map(fields => fields.sort()) + return Object.fromEntries( + Object.entries(indexes).map(([ modelName, index ]) => [ + modelName, + index.filter(fields => !fields.includes('id')).map(fields => fields.sort()) + ]) + ) } async _clearObject (modelName, id) { From 30778841aceabe3be8b3a009eb07b3dc7a309664 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Wed, 2 Feb 2022 15:55:15 +0200 Subject: [PATCH 11/40] 2.0.0-beta.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0b98d3d..654a2b2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@charge-tech/chargejs", - "version": "2.0.0-beta.1", + "version": "2.0.0-beta.2", "description": "The Charge Core JS implementation.", "main": "src/index.js", "engines": { From e5a55e159d597096020ceb456d0ed0cc1a443132 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Wed, 2 Feb 2022 16:04:02 +0200 Subject: [PATCH 12/40] feat(cache-improve): improved caching --- src/constants/index.js | 2 +- src/infra/BaseRepository.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/constants/index.js b/src/constants/index.js index bc6cbfa..8d53b7c 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -142,7 +142,7 @@ export const ERROR_TYPES = { CACHE_DISABLED: 'CacheDisabledError', INVALID_FILTER: 'InvalidFilterError', INVALID_FILTER_VALUE: 'InvalidFilterValueError', - INVALID_FILTER_TYPE: 'InvalidFIlterTypeError', + INVALID_FILTER_TYPE: 'InvalidFilterTypeError', INVALID_PAGINATE_PARAMS: 'InvalidPaginateParamsError' } diff --git a/src/infra/BaseRepository.js b/src/infra/BaseRepository.js index 96cb11f..40ebf4b 100644 --- a/src/infra/BaseRepository.js +++ b/src/infra/BaseRepository.js @@ -143,7 +143,7 @@ class BaseRepository { * @returns {Promise} entity * @throws {module:interface.standardError} */ - async findLatest (where = undefined, { rejectOnEmpty = true, ...opts } = {}) { + async findLatest (where = {}, { rejectOnEmpty = true, ...opts } = {}) { const [result] = await this.findAll(where, { limit: 1, ...opts From e1394f7365386bc7a6ed33a80e3c40f20540a542 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Wed, 2 Feb 2022 16:04:09 +0200 Subject: [PATCH 13/40] 2.0.0-beta.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 654a2b2..f4054b0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@charge-tech/chargejs", - "version": "2.0.0-beta.2", + "version": "2.0.0-beta.3", "description": "The Charge Core JS implementation.", "main": "src/index.js", "engines": { From 809f2bd19cf16c0afd104c11a6ae520d78a0506a Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Mon, 7 Feb 2022 13:26:15 +0200 Subject: [PATCH 14/40] feat(cache-improve): improved caching --- src/infra/redis/RedisRepository.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/infra/redis/RedisRepository.js b/src/infra/redis/RedisRepository.js index 21e9bcf..80dd8ed 100644 --- a/src/infra/redis/RedisRepository.js +++ b/src/infra/redis/RedisRepository.js @@ -196,7 +196,7 @@ class RedisRepository { async _clearList (key, values) { await this.redisStorage.listClear(key) this.transactionProvider.addRedisRollback( - () => this.redisStorage.pushToList(key, ...values) + () => this.redisStorage.listPush(key, ...values) ) } From 2e8ba988a2b9230ec0852169dc172d821a1bbec7 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Mon, 7 Feb 2022 13:26:57 +0200 Subject: [PATCH 15/40] 3.1.0-beta.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f4054b0..c6321ca 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@charge-tech/chargejs", - "version": "2.0.0-beta.3", + "version": "3.1.0-beta.4", "description": "The Charge Core JS implementation.", "main": "src/index.js", "engines": { From ad0f432f45d35d9bc7c671c8b854a4373e6def83 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Mon, 7 Feb 2022 13:31:43 +0200 Subject: [PATCH 16/40] 2.0.0-beta.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c6321ca..207600f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@charge-tech/chargejs", - "version": "3.1.0-beta.4", + "version": "2.0.0-beta.4", "description": "The Charge Core JS implementation.", "main": "src/index.js", "engines": { From 0a26132b4fcbdf058f05db43983d10e84554f12b Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Mon, 7 Feb 2022 13:40:58 +0200 Subject: [PATCH 17/40] feat(cache-improve): improved caching --- src/infra/redis/RedisRepository.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/infra/redis/RedisRepository.js b/src/infra/redis/RedisRepository.js index 80dd8ed..97420be 100644 --- a/src/infra/redis/RedisRepository.js +++ b/src/infra/redis/RedisRepository.js @@ -98,8 +98,8 @@ class RedisRepository { async _clearRelated (modelName, id) { const key = this._buildRelationsKey(modelName, id) const related = await this.redisStorage.getList(key) - await this._clearList(key, related) if (related.length) { + await this._clearList(key, related) await Promise.all( related.map(({ modelName, id }) => { return this._deleteObject(modelName, id) From 74df1243d998afce475d366969ece21c1d0af69e Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Mon, 7 Feb 2022 13:41:06 +0200 Subject: [PATCH 18/40] 2.0.0-beta.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 207600f..6273ce0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@charge-tech/chargejs", - "version": "2.0.0-beta.4", + "version": "2.0.0-beta.5", "description": "The Charge Core JS implementation.", "main": "src/index.js", "engines": { From d8e784edb3b6d0c6b5b91432a0129e2402bddf33 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Wed, 9 Feb 2022 14:13:40 +0200 Subject: [PATCH 19/40] feat(cache-improve): improved caching --- src/infra/redis/RedisRepository.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/infra/redis/RedisRepository.js b/src/infra/redis/RedisRepository.js index 97420be..8796bc0 100644 --- a/src/infra/redis/RedisRepository.js +++ b/src/infra/redis/RedisRepository.js @@ -149,7 +149,7 @@ class RedisRepository { } _getIncluded (entity, include) { - return include.reduce((result, { modelName, as, include }) => { + const result = include.reduce((result, { modelName, as, include }) => { const related = entity[as] if (related) { const relatedArray = Array.isArray(related) ? related : [related] @@ -165,6 +165,8 @@ class RedisRepository { } return result }, []) + console.log('INCLUDED:', result) + return result } _getById (modelName, id) { From b501fb2d0f7e5f7b7c9f6dde7c8d9923872176d6 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Wed, 9 Feb 2022 14:13:45 +0200 Subject: [PATCH 20/40] 2.0.0-beta.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6273ce0..5e57c59 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@charge-tech/chargejs", - "version": "2.0.0-beta.5", + "version": "2.0.0-beta.6", "description": "The Charge Core JS implementation.", "main": "src/index.js", "engines": { From fcf07a968e004fc415ac95ce65ca0a05ea24cf42 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Wed, 9 Feb 2022 15:23:15 +0200 Subject: [PATCH 21/40] feat(cache-improve): improved caching --- src/infra/redis/RedisRepository.js | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/infra/redis/RedisRepository.js b/src/infra/redis/RedisRepository.js index 8796bc0..c78726b 100644 --- a/src/infra/redis/RedisRepository.js +++ b/src/infra/redis/RedisRepository.js @@ -1,4 +1,3 @@ -import ret from 'bluebird/js/release/util' import { get } from 'dot-get' import isEqual from 'lodash/isEqual' import { REDIS_REPOSITORY_INITIALIZED, INVALID_FILTER, INVALID_FILTER_VALUE } from '../../errors' @@ -65,10 +64,10 @@ class RedisRepository { const idKey = this._buildIdKey(this.modelName, object.id) await this._saveObject(idKey, object) const cacheKeys = this._getObjectCacheKeys(this.modelName, object) - await Promise.all(cacheKeys.map( - key => this._saveObject(key, object.id) - )) - await this._storeIncluded(object) + await Promise.all([ + this._storeIncluded(object), + ...cacheKeys.map(key => this._saveObject(key, object.id)) + ]) return object } @@ -99,20 +98,20 @@ class RedisRepository { const key = this._buildRelationsKey(modelName, id) const related = await this.redisStorage.getList(key) if (related.length) { - await this._clearList(key, related) - await Promise.all( - related.map(({ modelName, id }) => { - return this._deleteObject(modelName, id) + await Promise.all([ + this._clearList(key, related), + ...related.map(({ modelName, id }) => { + return this._clearObject(modelName, id) }) - ) + ]) } } _normalizeIndexes (indexes) { return Object.fromEntries( - Object.entries(indexes).map(([ modelName, index ]) => [ + Object.entries(indexes).map(([modelName, index]) => [ modelName, - index.filter(fields => !fields.includes('id')).map(fields => fields.sort()) + index.filter(fields => !fields.includes('id')).map(fields => fields.sort()) ]) ) } @@ -165,7 +164,7 @@ class RedisRepository { } return result }, []) - console.log('INCLUDED:', result) + console.log('\n', entity.object, 'INCLUDED:', result) return result } From 47476aff27af376f4780d18b3e7c09adafd1edc8 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Wed, 9 Feb 2022 15:23:22 +0200 Subject: [PATCH 22/40] 2.0.0-beta.7 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5e57c59..beb5b08 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@charge-tech/chargejs", - "version": "2.0.0-beta.6", + "version": "2.0.0-beta.7", "description": "The Charge Core JS implementation.", "main": "src/index.js", "engines": { From 54359cd564ddd94073065de1d0411cb1b1f47fcf Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Wed, 9 Feb 2022 16:35:59 +0200 Subject: [PATCH 23/40] feat(cache-improve): improved caching --- src/infra/redis/RedisRepository.js | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/infra/redis/RedisRepository.js b/src/infra/redis/RedisRepository.js index c78726b..08778bc 100644 --- a/src/infra/redis/RedisRepository.js +++ b/src/infra/redis/RedisRepository.js @@ -62,11 +62,11 @@ class RedisRepository { async create (object) { const idKey = this._buildIdKey(this.modelName, object.id) - await this._saveObject(idKey, object) + await this._saveRow(idKey, object) const cacheKeys = this._getObjectCacheKeys(this.modelName, object) await Promise.all([ this._storeIncluded(object), - ...cacheKeys.map(key => this._saveObject(key, object.id)) + ...cacheKeys.map(key => this._saveRow(key, object.id)) ]) return object } @@ -83,15 +83,18 @@ class RedisRepository { } } - clear ({ id }, relationsOnly) { + clear ({ id }, relationsOnly = false) { return this._clear(this.modelName, id, relationsOnly) } - _clear (modelName, id, relationsOnly) { - return Promise.all([ - !relationsOnly ? this._clearObject(this.modelName, id) : null, + _clear (modelName, id, relationsOnly = false) { + const promises = [ this._clearRelated(modelName, id) - ].filter(Boolean)) + ] + if (!relationsOnly) { + promises.unshift(this._clearObject(modelName, id)) + } + return Promise.all(promises) } async _clearRelated (modelName, id) { @@ -120,11 +123,11 @@ class RedisRepository { const object = await this._getById(modelName, id) if (object) { const key = this._buildIdKey(modelName, id) - await this._deleteObject(key, object) + await this._deleteRow(key, object) const cacheKeys = this._getObjectCacheKeys(modelName, object) if (cacheKeys.length) { await Promise.all(cacheKeys.map( - key => this._deleteObject(key, id) + key => this._deleteRow(key, id) )) } } @@ -148,7 +151,7 @@ class RedisRepository { } _getIncluded (entity, include) { - const result = include.reduce((result, { modelName, as, include }) => { + return include.reduce((result, { modelName, as, include }) => { const related = entity[as] if (related) { const relatedArray = Array.isArray(related) ? related : [related] @@ -164,8 +167,6 @@ class RedisRepository { } return result }, []) - console.log('\n', entity.object, 'INCLUDED:', result) - return result } _getById (modelName, id) { @@ -187,7 +188,7 @@ class RedisRepository { ) } - async _saveObject (key, object) { + async _saveRow (key, object) { await this.redisStorage.saveObject(key, object) this.transactionProvider.addRedisRollback( () => this.redisStorage.deleteObject(key) @@ -201,7 +202,7 @@ class RedisRepository { ) } - async _deleteObject (key, object) { + async _deleteRow (key, object) { await this.redisStorage.deleteObject(key) this.transactionProvider.addRedisRollback( () => this.redisStorage.saveObject(key, object) From 89ad0972dff920fa4c1c8a1dd561d8b3d63b3465 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Wed, 9 Feb 2022 16:36:04 +0200 Subject: [PATCH 24/40] 2.0.0-beta.8 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index beb5b08..3f2764a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@charge-tech/chargejs", - "version": "2.0.0-beta.7", + "version": "2.0.0-beta.8", "description": "The Charge Core JS implementation.", "main": "src/index.js", "engines": { From 23b586528f0eacd78f3fc9c49374d7936b6d0054 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Wed, 9 Feb 2022 17:10:40 +0200 Subject: [PATCH 25/40] feat(cache-improve): improved caching --- src/constants/index.js | 1 + src/errors/index.js | 5 +++++ src/infra/BaseRepository.js | 9 ++++++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/constants/index.js b/src/constants/index.js index 8d53b7c..c294bf0 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -143,6 +143,7 @@ export const ERROR_TYPES = { INVALID_FILTER: 'InvalidFilterError', INVALID_FILTER_VALUE: 'InvalidFilterValueError', INVALID_FILTER_TYPE: 'InvalidFilterTypeError', + EMPTY_UPDATE_FIELDS: 'EmptyUpdateFields', INVALID_PAGINATE_PARAMS: 'InvalidPaginateParamsError' } diff --git a/src/errors/index.js b/src/errors/index.js index d54552f..4c61af3 100644 --- a/src/errors/index.js +++ b/src/errors/index.js @@ -38,6 +38,11 @@ export const INVALID_FILTER_TYPE = { code: ERROR_TYPES.INVALID_FILTER_TYPE } +export const EMPTY_UPDATE_FIELDS = { + message: 'No fileds to update', + code: ERROR_TYPES.EMPTY_UPDATE_FIELDS +} + export const INVALID_CURRENT_PAGE = { message: 'currentPage parameter should be a valid number', code: ERROR_TYPES.INVALID_PAGINATE_PARAMS diff --git a/src/infra/BaseRepository.js b/src/infra/BaseRepository.js index 40ebf4b..96d23a5 100644 --- a/src/infra/BaseRepository.js +++ b/src/infra/BaseRepository.js @@ -5,7 +5,8 @@ import { SEQUELIZE_NOT_FOUNT_ERROR, SEQUELIZE_VALIDATION_ERROR, INVALID_PAGE_SIZE, - INVALID_CURRENT_PAGE + INVALID_CURRENT_PAGE, + EMPTY_UPDATE_FIELDS } from '../errors' /** @@ -264,6 +265,12 @@ class BaseRepository { this._validateFilter(where) const filteredFields = filterFields ? this._filterPatchFields(updateFields) : updateFields + if (!Object.keys(filteredFields).length) { + throw this._getValidationError([{ + message: EMPTY_UPDATE_FIELDS.message, + path: 'updateFields' + }]) + } try { const filter = await this._getPatchFilter(where) const [, result] = await this.model.update(filteredFields, { From 90ed4e3c437a2df799ecba924859304e38d14653 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Wed, 9 Feb 2022 17:10:47 +0200 Subject: [PATCH 26/40] 2.0.0-beta.9 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3f2764a..9180894 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@charge-tech/chargejs", - "version": "2.0.0-beta.8", + "version": "2.0.0-beta.9", "description": "The Charge Core JS implementation.", "main": "src/index.js", "engines": { From de7b3d3c685a4e6e41907bd2a2927ffd3d907eec Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Fri, 25 Mar 2022 15:24:39 +0200 Subject: [PATCH 27/40] 2.0.0-beta.10 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ebdbffb..7493431 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@charge-tech/chargejs", - "version": "2.0.0-beta.9", + "version": "2.0.0-beta.10", "description": "The Charge Core JS implementation.", "main": "src/index.js", "engines": { From 00ee6239ab4f98c9c0b310012be94a9e5a855050 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Thu, 31 Mar 2022 15:32:10 +0300 Subject: [PATCH 28/40] 2.0.0-beta.11 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7493431..b59d3f0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@charge-tech/chargejs", - "version": "2.0.0-beta.10", + "version": "2.0.0-beta.11", "description": "The Charge Core JS implementation.", "main": "src/index.js", "engines": { From aab0f96504a789edbc8f76c205dc0b3119545ed1 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Thu, 31 Mar 2022 17:41:40 +0300 Subject: [PATCH 29/40] 2.0.0-beta.12 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b59d3f0..4d9ffd6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@charge-tech/chargejs", - "version": "2.0.0-beta.11", + "version": "2.0.0-beta.12", "description": "The Charge Core JS implementation.", "main": "src/index.js", "engines": { From ba777c32b25d72eda528641b5aea5a2188bd2f66 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Thu, 31 Mar 2022 19:59:31 +0300 Subject: [PATCH 30/40] 2.0.0-beta.13 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4d9ffd6..4542bd6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@charge-tech/chargejs", - "version": "2.0.0-beta.12", + "version": "2.0.0-beta.13", "description": "The Charge Core JS implementation.", "main": "src/index.js", "engines": { From 133eec4806c71848c0f5424c4d61fb4e82d6e0d3 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Mon, 4 Apr 2022 20:10:35 +0300 Subject: [PATCH 31/40] feat(error): errors consts --- src/errors/index.js | 5 +++++ src/interfaces/ServiceCommunicator.js | 11 +++++++---- tests/domain.test.js | 1 - 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/errors/index.js b/src/errors/index.js index 5700f9b..dfa312d 100644 --- a/src/errors/index.js +++ b/src/errors/index.js @@ -17,6 +17,11 @@ export const VALIDATION_ERROR = { code: ERROR_TYPES.VALIDATION_ERROR } +export const CONFLICT_ERROR = { + message: 'Conflict error', + code: ERROR_TYPES.CONFLICT +} + export const INVALID_ENV = { message: `Invalid environment. Allowed values ${ALLOWED_ENVIRONMENTS}`, code: CODES.INVALID_ENV diff --git a/src/interfaces/ServiceCommunicator.js b/src/interfaces/ServiceCommunicator.js index fde8b98..b3cb3b0 100644 --- a/src/interfaces/ServiceCommunicator.js +++ b/src/interfaces/ServiceCommunicator.js @@ -1,5 +1,6 @@ import axios from 'axios' import Status from 'http-status' +import { NOT_FOUND, VALIDATION_ERROR, CONFLICT_ERROR } from '../errors' export class ServiceCommunicator { constructor ({ @@ -31,7 +32,7 @@ export class ServiceCommunicator { } _getStandardError (error) { - const type = this._getErrorType(error.type) + const type = this._getErrorCode(error.type) const { message, errors = [] } = error return this.standardError({ type, @@ -44,12 +45,14 @@ export class ServiceCommunicator { }) } - _getErrorType (type) { + _getErrorCode (type) { switch (type) { case Status['400_NAME']: - return this.logmsg.errors.validationError + return VALIDATION_ERROR.code case Status['404_NAME']: - return this.logmsg.errors.notFoundError + return NOT_FOUND.code + case Status['409_NAME']: + return CONFLICT_ERROR.code default: return type } diff --git a/tests/domain.test.js b/tests/domain.test.js index fcde8eb..cbbcff9 100644 --- a/tests/domain.test.js +++ b/tests/domain.test.js @@ -14,7 +14,6 @@ describe('domain', function () { it('it set meta correctly', function () { const meta = 'test' base.setMeta(meta) - console.log(base.meta) assert.deepStrictEqual(base.meta, meta) }) it('it should set masked correctly', function () { From 3ec884d342f1ef572f2aba101d6b1c9c31a1be80 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Mon, 4 Apr 2022 20:11:01 +0300 Subject: [PATCH 32/40] 2.0.0-beta.14 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4542bd6..0b15b56 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@charge-tech/chargejs", - "version": "2.0.0-beta.13", + "version": "2.0.0-beta.14", "description": "The Charge Core JS implementation.", "main": "src/index.js", "engines": { From 486b21a5125352f9e036c2e626aaa418904bf5ef Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Tue, 17 May 2022 18:21:28 +0300 Subject: [PATCH 33/40] fix(destroy): fixed delete func --- src/config/index.js | 2 +- src/infra/BaseRepository.js | 10 +++++++--- src/infra/redis/RedisRepository.js | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/config/index.js b/src/config/index.js index aafa21f..08fd766 100644 --- a/src/config/index.js +++ b/src/config/index.js @@ -324,7 +324,7 @@ export const VALIDATION = { specialChar: /\W/, printableChars: /^[A-Za-z0-9 <>@!#$%&'*+-/=?^_`(){|}~[\]\\:;,./<>?"]+$/, accountName: /^[A-Za-z0-9 ]+$/, - businessName: /^[A-Za-z0-9 .`~!@#$%^&*()_:";'{}[\]+<>?,/]+$/, + businessName: /^[A-Za-z0-9 .`~!@#$%^&*()_:";'{}\[\]+<>?,/]+$/, street: /^[A-Za-z0-9 .]+$/, city: /[A-Za-z .]+$/, stateCode: /^[A-Za-z]+$/, diff --git a/src/infra/BaseRepository.js b/src/infra/BaseRepository.js index 61b1896..d015a7c 100644 --- a/src/infra/BaseRepository.js +++ b/src/infra/BaseRepository.js @@ -321,14 +321,18 @@ class BaseRepository { this._validateFilter(where) try { - const filter = await this._getPatchFilter(where) - const [, result] = await this.model.destroy({ - where: filter, + const result = await this.model.findOne({ + where, + distinct: true, transaction: this._getTransaction() }) if (!result) { throw this._getNotFoundError() } + await this.model.destroy({ + where: filter, + transaction: this._getTransaction() + }) const json = result.toJSON() await this._clearCache(json) return this.mapper.toEntity(json) diff --git a/src/infra/redis/RedisRepository.js b/src/infra/redis/RedisRepository.js index 08778bc..8cb5708 100644 --- a/src/infra/redis/RedisRepository.js +++ b/src/infra/redis/RedisRepository.js @@ -221,7 +221,7 @@ class RedisRepository { value, type: typeof value })) - const error = new Error(`${INVALID_FILTER_VALUE.message}: Invalid fields: ${fields}`) + const error = new Error(`${INVALID_FILTER_VALUE.message}: Invalid fields: ${JSON.stringify(fields)}`) error.type = INVALID_FILTER_VALUE.code throw error } From dc67c4dd0187fa2c5cd1d233ecba726e22c85ff1 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Tue, 17 May 2022 18:21:44 +0300 Subject: [PATCH 34/40] 2.0.0-beta.15 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0b15b56..e0f90a5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@charge-tech/chargejs", - "version": "2.0.0-beta.14", + "version": "2.0.0-beta.15", "description": "The Charge Core JS implementation.", "main": "src/index.js", "engines": { From 6687cdbdf11df4b1c185c6335655a6785418e8ee Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Tue, 17 May 2022 18:58:17 +0300 Subject: [PATCH 35/40] fix(destroy): fixed delete func --- src/config/index.js | 2 +- src/infra/BaseRepository.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config/index.js b/src/config/index.js index 08fd766..aafa21f 100644 --- a/src/config/index.js +++ b/src/config/index.js @@ -324,7 +324,7 @@ export const VALIDATION = { specialChar: /\W/, printableChars: /^[A-Za-z0-9 <>@!#$%&'*+-/=?^_`(){|}~[\]\\:;,./<>?"]+$/, accountName: /^[A-Za-z0-9 ]+$/, - businessName: /^[A-Za-z0-9 .`~!@#$%^&*()_:";'{}\[\]+<>?,/]+$/, + businessName: /^[A-Za-z0-9 .`~!@#$%^&*()_:";'{}[\]+<>?,/]+$/, street: /^[A-Za-z0-9 .]+$/, city: /[A-Za-z .]+$/, stateCode: /^[A-Za-z]+$/, diff --git a/src/infra/BaseRepository.js b/src/infra/BaseRepository.js index d015a7c..f76c619 100644 --- a/src/infra/BaseRepository.js +++ b/src/infra/BaseRepository.js @@ -330,7 +330,7 @@ class BaseRepository { throw this._getNotFoundError() } await this.model.destroy({ - where: filter, + where: { id: result.id }, transaction: this._getTransaction() }) const json = result.toJSON() From b8abc34995aed8a5714f84b8ac4c2832bea4eb94 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Tue, 17 May 2022 18:58:31 +0300 Subject: [PATCH 36/40] 2.0.0-beta.16 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e0f90a5..d3edefe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@charge-tech/chargejs", - "version": "2.0.0-beta.15", + "version": "2.0.0-beta.16", "description": "The Charge Core JS implementation.", "main": "src/index.js", "engines": { From e2003c9adf1ce12a5acff459c38ddfdd83056f52 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Tue, 7 Jun 2022 17:05:38 +0300 Subject: [PATCH 37/40] 2.0.0-beta.17 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d3edefe..89813b2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@charge-tech/chargejs", - "version": "2.0.0-beta.16", + "version": "2.0.0-beta.17", "description": "The Charge Core JS implementation.", "main": "src/index.js", "engines": { From ddfa03c5675821672e3d47f8962f06fa76c8d755 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Tue, 5 Jul 2022 17:40:20 +0300 Subject: [PATCH 38/40] 2.0.0-beta.18 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 89813b2..41bc743 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@charge-tech/chargejs", - "version": "2.0.0-beta.17", + "version": "2.0.0-beta.18", "description": "The Charge Core JS implementation.", "main": "src/index.js", "engines": { From 0870591780dc8fc7c958109e8e6dd61a9648e77d Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Tue, 5 Jul 2022 17:53:31 +0300 Subject: [PATCH 39/40] feat(upd-caching): fixed tests --- tests/infra/BaseRepository.test.js | 31 +++++++++++++----------------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/tests/infra/BaseRepository.test.js b/tests/infra/BaseRepository.test.js index 6970e89..b3cb8ee 100644 --- a/tests/infra/BaseRepository.test.js +++ b/tests/infra/BaseRepository.test.js @@ -651,8 +651,8 @@ describe('BaseRepository', function () { const domainEntity = EntityStub(obj) it('should delete entity', async function () { - sinon.stub(baseRepository, '_getPatchFilter').callsFake(() => where) - sinon.stub(SequelizeModelStub, 'destroy').callsFake(() => [1, dbEntry]) + sinon.stub(SequelizeModelStub, 'findOne').callsFake(() => dbEntry) + sinon.stub(SequelizeModelStub, 'destroy').callsFake(() => true) sinon.spy(baseRepository, '_getNotFoundError') sinon.stub(EntityMapperStub, 'toEntity').callsFake(() => domainEntity) sinon.spy(RedisRepositoryStub, 'clear') @@ -665,10 +665,8 @@ describe('BaseRepository', function () { const res = await baseRepository.delete(where) - baseRepository._getPatchFilter.should.have.been.calledOnce - baseRepository._getPatchFilter.should.have.been.calledWith(where) SequelizeModelStub.destroy.should.have.been.calledOnce - expect(SequelizeModelStub.destroy.getCall(0).args[0].where).to.deep.equal(where) + expect(SequelizeModelStub.destroy.getCall(0).args[0].where).to.deep.equal({ id: dbEntry.id }) baseRepository._getNotFoundError.should.have.not.been.called EntityMapperStub.toEntity.should.have.been.calledOnce EntityMapperStub.toEntity.should.have.been.calledWith(obj) @@ -676,15 +674,15 @@ describe('BaseRepository', function () { RedisRepositoryStub.clear.should.have.been.calledWith(obj) expect(res).to.deep.equal(domainEntity) - baseRepository._getPatchFilter.restore() SequelizeModelStub.destroy.restore() + SequelizeModelStub.findOne.restore() baseRepository._getNotFoundError.restore() EntityMapperStub.toEntity.restore() RedisRepositoryStub.clear.restore() }) it('should delete entity (cacheDisabled=true)', async function () { - sinon.stub(baseRepository, '_getPatchFilter').callsFake(() => where) + sinon.stub(SequelizeModelStub, 'findOne').callsFake(() => dbEntry) sinon.stub(SequelizeModelStub, 'destroy').callsFake(() => [1, dbEntry]) sinon.spy(baseRepository, '_getNotFoundError') sinon.stub(EntityMapperStub, 'toEntity').callsFake(() => domainEntity) @@ -699,25 +697,23 @@ describe('BaseRepository', function () { const res = await baseRepository.delete(where) - baseRepository._getPatchFilter.should.have.been.calledOnce - baseRepository._getPatchFilter.should.have.been.calledWith(where) SequelizeModelStub.destroy.should.have.been.calledOnce - expect(SequelizeModelStub.destroy.getCall(0).args[0].where).to.deep.equal(where) + expect(SequelizeModelStub.destroy.getCall(0).args[0].where).to.deep.equal({ id: dbEntry.id }) RedisRepositoryStub.clear.should.have.been.calledWith(obj, true) baseRepository._getNotFoundError.should.have.not.been.called EntityMapperStub.toEntity.should.have.been.calledOnce EntityMapperStub.toEntity.should.have.been.calledWith(obj) expect(res).to.deep.equal(domainEntity) - baseRepository._getPatchFilter.restore() + SequelizeModelStub.findOne.restore() SequelizeModelStub.destroy.restore() baseRepository._getNotFoundError.restore() EntityMapperStub.toEntity.restore() RedisRepositoryStub.clear.restore() }) - it('should throw NotFound on patch entity', async function () { - sinon.stub(baseRepository, '_getPatchFilter').callsFake(() => where) + it('should throw NotFound on delete entity', async function () { + sinon.stub(SequelizeModelStub, 'findOne').callsFake(() => false) sinon.stub(SequelizeModelStub, 'destroy').callsFake(() => [0]) sinon.spy(baseRepository, '_getNotFoundError') sinon.spy(EntityMapperStub, 'toEntity') @@ -736,16 +732,15 @@ describe('BaseRepository', function () { error = e } - baseRepository._getPatchFilter.should.have.been.calledOnce - baseRepository._getPatchFilter.should.have.been.calledWith(where) - SequelizeModelStub.destroy.should.have.been.calledOnce - expect(SequelizeModelStub.destroy.getCall(0).args[0].where).to.deep.equal(where) + SequelizeModelStub.findOne.should.have.been.calledOnce + SequelizeModelStub.destroy.should.have.not.been.calledOnce + expect(SequelizeModelStub.findOne.getCall(0).args[0].where).to.deep.equal(where) baseRepository._getNotFoundError.should.have.been.calledOnce EntityMapperStub.toEntity.should.have.not.been.called RedisRepositoryStub.clear.should.have.not.been.called expect(error.message).to.deep.equal('NotFoundError') - baseRepository._getPatchFilter.restore() + SequelizeModelStub.findOne.restore() SequelizeModelStub.destroy.restore() baseRepository._getNotFoundError.restore() EntityMapperStub.toEntity.restore() From 489a5f23e60d15ca1482679924d9879831f665d3 Mon Sep 17 00:00:00 2001 From: Dmytro Kulchytskyi Date: Tue, 5 Jul 2022 17:53:54 +0300 Subject: [PATCH 40/40] 2.0.0-beta.19 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 41bc743..da9aab6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@charge-tech/chargejs", - "version": "2.0.0-beta.18", + "version": "2.0.0-beta.19", "description": "The Charge Core JS implementation.", "main": "src/index.js", "engines": {