Skip to content

Commit

Permalink
feat(api): add idempotent call to insert feature
Browse files Browse the repository at this point in the history
  • Loading branch information
xav-car committed Dec 2, 2024
1 parent 3e41ae2 commit 41fe95b
Show file tree
Hide file tree
Showing 5 changed files with 9 additions and 51 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { HttpErrors } from '../../shared/application/http-errors.js';
import { DomainErrorMappingConfiguration } from '../../shared/application/models/domain-error-mapping-configuration.js';
import {
AlreadyExistingOrganizationFeatureError,
DpoEmailInvalid,
FeatureNotFound,
FeatureParamsNotProcessable,
Expand All @@ -16,10 +15,6 @@ const organizationalEntitiesDomainErrorMappingConfiguration = [
name: UnableToAttachChildOrganizationToParentOrganizationError.name,
httpErrorFn: (error) => new HttpErrors.ConflictError(error.message, error.code, error.meta),
},
{
name: AlreadyExistingOrganizationFeatureError.name,
httpErrorFn: (error) => new HttpErrors.ConflictError(error.message, error.code, error.meta),
},
{
name: OrganizationNotFound.name,
httpErrorFn: (error) => new HttpErrors.UnprocessableEntityError(error.message, error.code, error.meta),
Expand Down
13 changes: 0 additions & 13 deletions api/src/organizational-entities/domain/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,6 @@ class UnableToAttachChildOrganizationToParentOrganizationError extends DomainErr
}
}

class AlreadyExistingOrganizationFeatureError extends DomainError {
constructor({
code = 'ALREADY_EXISTING_ORGANIZATION_FEATURE',
message = 'Unable to add feature to organization',
meta,
} = {}) {
super(message);
this.code = code;
this.meta = meta;
}
}

class DpoEmailInvalid extends DomainError {
constructor({ code = 'DPO_EMAIL_INVALID', message = 'DPO email invalid', meta } = {}) {
super(message);
Expand Down Expand Up @@ -72,7 +60,6 @@ class FeatureParamsNotProcessable extends DomainError {
}

export {
AlreadyExistingOrganizationFeatureError,
DpoEmailInvalid,
FeatureNotFound,
FeatureParamsNotProcessable,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*/
import * as knexUtils from '../../../../src/shared/infrastructure/utils/knex-utils.js';
import { DomainTransaction } from '../../../shared/domain/DomainTransaction.js';
import { AlreadyExistingOrganizationFeatureError, FeatureNotFound, OrganizationNotFound } from '../../domain/errors.js';
import { FeatureNotFound, OrganizationNotFound } from '../../domain/errors.js';
import { OrganizationFeatureItem } from '../../domain/models/OrganizationFeatureItem.js';

/**
Expand All @@ -13,21 +13,18 @@ import { OrganizationFeatureItem } from '../../domain/models/OrganizationFeature
* @typedef {import('../../domain/models/OrganizationFeatureItem.js').OrganizationFeatureItem} OrganizationFeatureItem
*/

const DEFAULT_BATCH_SIZE = 100;

/**
**
* @param {OrganizationFeature[]} organizations
*/
async function saveInBatch(organizationFeatures, batchSize = DEFAULT_BATCH_SIZE) {
async function saveInBatch(organizationFeatures) {
try {
const knexConn = DomainTransaction.getConnection();
await knexConn.batchInsert('organization-features', organizationFeatures, batchSize);
await knexConn('organization-features')
.insert(organizationFeatures)
.onConflict(['featureId', 'organizationId'])
.ignore();
} catch (err) {
if (knexUtils.isUniqConstraintViolated(err)) {
throw new AlreadyExistingOrganizationFeatureError();
}

if (knexUtils.foreignKeyConstraintViolated(err) && err.constraint.includes('featureid')) {
throw new FeatureNotFound();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { organizationAdminController } from '../../../../../src/organizational-entities/application/organization/organization.admin.controller.js';
import * as organizationAdminRoutes from '../../../../../src/organizational-entities/application/organization/organization.admin.route.js';
import {
AlreadyExistingOrganizationFeatureError,
DpoEmailInvalid,
FeatureNotFound,
FeatureParamsNotProcessable,
Expand Down Expand Up @@ -93,20 +92,6 @@ describe('Integration | Organizational Entities | Application | Route | Admin |
expect(response.statusCode).to.equal(422);
});
});

context('when trying to add already existing feature on organization', function () {
it('returns a 409 HTTP status code', async function () {
organizationAdminController.addOrganizationFeatureInBatch.rejects(
new AlreadyExistingOrganizationFeatureError(),
);

// when
const response = await httpTestServer.request(method, url, payload);

// then
expect(response.statusCode).to.equal(409);
});
});
});

describe('POST /api/admin/organizations/update-organizations', function () {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import {
AlreadyExistingOrganizationFeatureError,
FeatureNotFound,
OrganizationNotFound,
} from '../../../../../src/organizational-entities/domain/errors.js';
import { FeatureNotFound, OrganizationNotFound } from '../../../../../src/organizational-entities/domain/errors.js';
import { OrganizationFeature } from '../../../../../src/organizational-entities/domain/models/OrganizationFeature.js';
import { OrganizationFeatureItem } from '../../../../../src/organizational-entities/domain/models/OrganizationFeatureItem.js';
import * as organizationFeatureRepository from '../../../../../src/organizational-entities/infrastructure/repositories/organization-feature-repository.js';
Expand Down Expand Up @@ -54,7 +50,7 @@ describe('Integration | Repository | Organization-for-admin', function () {
expect(result[1].params).to.deep.equal(organizationFeatures[1].params);
});

it('throws an error if organization feature already exists', async function () {
it('should passe even if organization feature already exists', async function () {
databaseBuilder.factory.buildOrganizationFeature({ organizationId: organization.id, featureId: feature.id });
await databaseBuilder.commit();

Expand All @@ -67,9 +63,7 @@ describe('Integration | Repository | Organization-for-admin', function () {
];

// when
const error = await catchErr(organizationFeatureRepository.saveInBatch)(organizationFeatures);

expect(error).to.be.instanceOf(AlreadyExistingOrganizationFeatureError);
expect(await organizationFeatureRepository.saveInBatch(organizationFeatures)).to.not.throws;
});

it('throws an error if organization does not exists', async function () {
Expand Down

0 comments on commit 41fe95b

Please sign in to comment.