Skip to content
This repository has been archived by the owner on Mar 23, 2022. It is now read-only.

Commit

Permalink
ADD - Unit name reference controller to update the references (Raenon…
Browse files Browse the repository at this point in the history
  • Loading branch information
RaenonX committed Aug 5, 2021
1 parent fff2f1e commit 31a66f3
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 11 deletions.
2 changes: 1 addition & 1 deletion src/api-def
Submodule api-def updated 1 files
+1 −0 api/responseCode.ts
114 changes: 113 additions & 1 deletion src/endpoints/data/unitNameRef/controller.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import {mongoExecInTransaction} from '../../../../test/utils/mongo';
import {SupportedLanguages} from '../../../api-def/api';
import {Application, createApp} from '../../../app';
import {UnitNameRefController} from './controller';
import {UnitNameRefEntry} from './model';
import {DuplicatedNamesError} from './error';
import {UnitNameRefEntry, UnitNameRefEntryDocumentKey} from './model';


describe('Unit name reference data controller', () => {
Expand Down Expand Up @@ -80,4 +82,114 @@ describe('Unit name reference data controller', () => {

expect(data).toStrictEqual([]);
});

it('fails to update if the names are duplicated', async () => {
const fn = async () => {
await UnitNameRefController.updateRefs(
app.mongoClient,
SupportedLanguages.EN,
[
{unitId: 10950101, name: 'Unit 1'},
{unitId: 10950201, name: 'Unit 1'},
],
);
};

await expect(fn).rejects.toThrow(DuplicatedNamesError);
});

it('keeps the original name references if failed to update', async () => {
const dataArray = [
new UnitNameRefEntry({lang: SupportedLanguages.EN, name: 'Unit A', unitId: 10950101}),
new UnitNameRefEntry({lang: SupportedLanguages.EN, name: 'Unit B', unitId: 10850101}),
].map((entry) => entry.toObject());
await UnitNameRefEntry.getCollection(app.mongoClient).insertMany(dataArray);

const fn = async () => {
await UnitNameRefController.updateRefs(
app.mongoClient,
SupportedLanguages.EN,
[
{unitId: 10950101, name: 'Unit 1'},
{unitId: 10950201, name: 'Unit 1'},
],
);
};

await expect(fn).rejects.toThrow(DuplicatedNamesError);

await mongoExecInTransaction(app.mongoClient, async () => {
expect((await UnitNameRefEntry.getCollection(app.mongoClient).find().toArray()).length).toBe(2);
});
});

it('updates even if multiple entries share the same unit', async () => {
await UnitNameRefController.updateRefs(
app.mongoClient,
SupportedLanguages.EN,
[
{unitId: 10950101, name: 'Unit 1'},
{unitId: 10950101, name: 'Unit 2'},
],
);

await mongoExecInTransaction(app.mongoClient, async () => {
const data = await UnitNameRefEntry.getCollection(app.mongoClient).find().toArray();
expect(data.map((entry) => entry[UnitNameRefEntryDocumentKey.name]).sort()).toStrictEqual(['Unit 1', 'Unit 2']);
});
});

it('accepts empty update unit name ref list', async () => {
await UnitNameRefController.updateRefs(app.mongoClient, SupportedLanguages.EN, []);

await mongoExecInTransaction(app.mongoClient, async () => {
const data = await UnitNameRefEntry.getCollection(app.mongoClient).find().toArray();
expect(data.map((entry) => entry[UnitNameRefEntryDocumentKey.name]).sort()).toStrictEqual([]);
});
});

it('removes entries that are not contained in the update list', async () => {
const dataArray = [
new UnitNameRefEntry({lang: SupportedLanguages.EN, name: 'Unit A', unitId: 10950101}),
new UnitNameRefEntry({lang: SupportedLanguages.EN, name: 'Unit 1', unitId: 10850101}),
].map((entry) => entry.toObject());
await UnitNameRefEntry.getCollection(app.mongoClient).insertMany(dataArray);

await UnitNameRefController.updateRefs(
app.mongoClient,
SupportedLanguages.EN,
[
{unitId: 10850101, name: 'Unit 1'},
{unitId: 10950101, name: 'Unit 2'},
],
);

await mongoExecInTransaction(app.mongoClient, async () => {
const data = await UnitNameRefEntry.getCollection(app.mongoClient).find().toArray();
expect(data.map((entry) => entry[UnitNameRefEntryDocumentKey.name]).sort()).toStrictEqual(['Unit 1', 'Unit 2']);
});
});

it('updates the entries in the given language only', async () => {
const dataArray = [
new UnitNameRefEntry({lang: SupportedLanguages.EN, name: 'Unit A', unitId: 10950101}),
new UnitNameRefEntry({lang: SupportedLanguages.EN, name: 'Unit B', unitId: 10850101}),
new UnitNameRefEntry({lang: SupportedLanguages.CHT, name: 'Unit 1', unitId: 10850101}),
].map((entry) => entry.toObject());
await UnitNameRefEntry.getCollection(app.mongoClient).insertMany(dataArray);

await UnitNameRefController.updateRefs(
app.mongoClient,
SupportedLanguages.EN,
[{
unitId: 10850101,
name: 'Unit C',
}],
);

await mongoExecInTransaction(app.mongoClient, async () => {
const data = await UnitNameRefEntry.getCollection(app.mongoClient).find().toArray();
expect(data.map((entry) => entry[UnitNameRefEntryDocumentKey.name]).sort()).toStrictEqual(['Unit 1', 'Unit C']);
});
});
});
52 changes: 50 additions & 2 deletions src/endpoints/data/unitNameRef/controller.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import {MongoClient} from 'mongodb';
import {MongoClient, MongoError} from 'mongodb';

import {UnitNameRefData, UnitNameRefEntry as UnitNameRefEntryApi, SupportedLanguages} from '../../../api-def/api';
import {MultiLingualDocumentKey} from '../../../base/model/multiLang';
import {UnitNameRefEntry, UnitNameRefEntryDocumentKey} from './model';
import {execTransaction} from '../../../utils/mongodb';
import {DuplicatedNamesError} from './error';
import {UnitNameRefEntry, UnitNameRefEntryDocument, UnitNameRefEntryDocumentKey} from './model';


/**
Expand Down Expand Up @@ -47,4 +49,50 @@ export class UnitNameRefController {
}))
.toArray();
}

/**
* Update all unit name references in the given ``lang``.
*
* @param {MongoClient} mongoClient mongo client
* @param {SupportedLanguages} lang language of the unit name references to update
* @param {Array<UnitNameRefEntryApi>} refs list of unit name references to use in the given language
* @return {Promise<Array<UnitNameRefEntryApi>>} list of unit name references
*/
static async updateRefs(
mongoClient: MongoClient,
lang: SupportedLanguages,
refs: Array<UnitNameRefEntryApi>,
): Promise<void> {
await execTransaction(
mongoClient,
async (session) => {
const collection = UnitNameRefEntry.getCollection(mongoClient);

await collection.deleteMany({[MultiLingualDocumentKey.language]: lang}, {session});

if (!refs.length) {
// No references to add
return;
}

try {
await collection.insertMany(
refs.map((entry) => ({
[UnitNameRefEntryDocumentKey.name]: entry.name,
[UnitNameRefEntryDocumentKey.unitId]: entry.unitId,
[MultiLingualDocumentKey.language]: lang,
} as UnitNameRefEntryDocument)),
{session},
);
} catch (e) {
if (e instanceof MongoError && e.code === 11000) {
// E11000 for duplicated key
throw new DuplicatedNamesError(e.errmsg);
} else {
throw e; // let other type of error bubble up
}
}
},
);
}
}
16 changes: 16 additions & 0 deletions src/endpoints/data/unitNameRef/error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {CustomError} from '../../../base/error';


/**
* Error to be thrown if there are multiple units sharing the same name.
*/
export class DuplicatedNamesError extends CustomError {
/**
* Construct an duplicated names error.
*
* @param {string} msg other error message to be displayed to help debugging
*/
constructor(msg: string) {
super(`There are duplicated unit names: ${msg}`);
}
}
10 changes: 3 additions & 7 deletions src/endpoints/data/unitNameRef/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,10 @@ export class UnitNameRefEntry extends Document {
*/
static getCollection(mongoClient: MongoClient): Collection {
return super.getCollectionWithInfo(mongoClient, dbInfo, ((collection) => {
// For getting the unit references
collection.createIndex(MultiLingualDocumentKey.language);
collection.createIndex(
[
{[MultiLingualDocumentKey.language]: 1},
{[UnitNameRefEntryDocumentKey.name]: 1},
],
{unique: true},
);
// For preventing duplicated entries
collection.createIndex(UnitNameRefEntryDocumentKey.name, {unique: true});
}));
}

Expand Down

0 comments on commit 31a66f3

Please sign in to comment.