Skip to content

Commit

Permalink
Upsert settings (#261)
Browse files Browse the repository at this point in the history
* refactor: make settings tests independent

* feat: implement upsert

* test: upsert

* fix: update schemas

* fix: tests
  • Loading branch information
jkoenig134 committed Sep 2, 2024
1 parent c1c9e0a commit 00d2bba
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,16 @@ import {
GetSettingsRequest,
GetSettingsUseCase,
UpdateSettingRequest,
UpdateSettingUseCase
UpdateSettingUseCase,
UpsertSettingByKeyRequest,
UpsertSettingByKeyUseCase
} from "../../../useCases";

export class SettingsFacade {
public constructor(
@Inject private readonly createSettingUseCase: CreateSettingUseCase,
@Inject private readonly updateSettingUseCase: UpdateSettingUseCase,
@Inject private readonly upsertSettingByKeyUseCase: UpsertSettingByKeyUseCase,
@Inject private readonly deleteSettingUseCase: DeleteSettingUseCase,
@Inject private readonly getSettingsUseCase: GetSettingsUseCase,
@Inject private readonly getSettingUseCase: GetSettingUseCase,
Expand Down Expand Up @@ -49,4 +52,8 @@ export class SettingsFacade {
public async updateSetting(request: UpdateSettingRequest): Promise<Result<SettingDTO, ApplicationError>> {
return await this.updateSettingUseCase.execute(request);
}

public async upsertSettingByKey(request: UpsertSettingByKeyRequest): Promise<Result<SettingDTO, ApplicationError>> {
return await this.upsertSettingByKeyUseCase.execute(request);
}
}
21 changes: 21 additions & 0 deletions packages/runtime/src/useCases/common/Schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20357,6 +20357,27 @@ export const UpdateSettingRequest: any = {
}
}

export const UpsertSettingByKeyRequest: any = {
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/UpsertSettingByKeyRequest",
"definitions": {
"UpsertSettingByKeyRequest": {
"type": "object",
"properties": {
"key": {
"type": "string"
},
"value": {}
},
"required": [
"key",
"value"
],
"additionalProperties": false
}
}
}

export const DownloadFileRequest: any = {
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/DownloadFileRequest",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Serializable } from "@js-soft/ts-serval";
import { Result } from "@js-soft/ts-utils";
import { SettingsController } from "@nmshd/consumption";
import { AccountController } from "@nmshd/transport";
import { Inject } from "typescript-ioc";
import { SettingDTO } from "../../../types";
import { SchemaRepository, SchemaValidator, UseCase } from "../../common";
import { SettingMapper } from "./SettingMapper";

export interface UpsertSettingByKeyRequest {
key: string;
value: any;
}

class Validator extends SchemaValidator<UpsertSettingByKeyRequest> {
public constructor(@Inject schemaRepository: SchemaRepository) {
super(schemaRepository.getSchema("UpsertSettingByKeyRequest"));
}
}

export class UpsertSettingByKeyUseCase extends UseCase<UpsertSettingByKeyRequest, SettingDTO> {
public constructor(
@Inject private readonly settingController: SettingsController,
@Inject private readonly accountController: AccountController,
@Inject validator: Validator
) {
super(validator);
}

protected async executeInternal(request: UpsertSettingByKeyRequest): Promise<Result<SettingDTO>> {
const settings = await this.settingController.getSettings({ key: request.key });

const newValue = Serializable.fromUnknown(request.value);

if (settings.length === 0) {
const setting = await this.settingController.createSetting({ key: request.key, value: newValue });
await this.accountController.syncDatawallet();
return Result.ok(SettingMapper.toSettingDTO(setting));
}

const latestSetting = settings.reduce((prev, current) => (prev.createdAt > current.createdAt ? prev : current));

latestSetting.value = newValue;
await this.settingController.updateSetting(latestSetting);
await this.accountController.syncDatawallet();

return Result.ok(SettingMapper.toSettingDTO(latestSetting));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from "./GetSettingByKey";
export * from "./GetSettings";
export * from "./SettingMapper";
export * from "./UpdateSetting";
export * from "./UpsertSettingByKey";
72 changes: 56 additions & 16 deletions packages/runtime/test/consumption/settings.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,39 @@ beforeAll(async () => {
const runtimeServices = await runtimeServiceProvider.launch(1);
consumptionServices = runtimeServices[0].consumption;
}, 30000);

afterAll(async () => await runtimeServiceProvider.stop());

describe("Settings", () => {
const value = { aKey: "a-value" };
let settingId: string;
afterEach(async () => {
const settings = await consumptionServices.settings.getSettings({});
for (const setting of settings.value) {
await consumptionServices.settings.deleteSetting({ id: setting.id });
}
});

describe("Settings", () => {
test("should create a setting", async () => {
const result = await consumptionServices.settings.createSetting({
key: "a-key",
value: value
});
const value = { aKey: "a-value" };
const result = await consumptionServices.settings.createSetting({ key: "a-key", value: value });
expect(result).toBeSuccessful();

const setting = result.value;
settingId = setting.id;
});

test("should get the setting", async () => {
const result = await consumptionServices.settings.getSetting({ id: settingId });
const value = { aKey: "a-value" };
const createSettingResult = await consumptionServices.settings.createSetting({ key: "a-key", value: value });

const result = await consumptionServices.settings.getSetting({ id: createSettingResult.value.id });
expect(result).toBeSuccessful();

const setting = result.value;
settingId = setting.id;

expect(setting.value).toStrictEqual(value);
});

test("should contain the setting in the list of settings", async () => {
const value = { aKey: "a-value" };
const settingId = (await consumptionServices.settings.createSetting({ key: "a-key", value: value })).value.id;

const result = await consumptionServices.settings.getSettings({});
expect(result).toBeSuccessful();

Expand All @@ -50,6 +55,9 @@ describe("Settings", () => {
});

test("should edit the setting", async () => {
const value = { aKey: "a-value" };
const settingId = (await consumptionServices.settings.createSetting({ key: "a-key", value: value })).value.id;

const newValue = { aKey: "another-Value" };
const updateResult = await consumptionServices.settings.updateSetting({
id: settingId,
Expand All @@ -65,6 +73,9 @@ describe("Settings", () => {
});

test("should delete the setting", async () => {
const value = { aKey: "a-value" };
const settingId = (await consumptionServices.settings.createSetting({ key: "a-key", value: value })).value.id;

const deleteResult = await consumptionServices.settings.deleteSetting({ id: settingId });
expect(deleteResult).toBeSuccessful();

Expand All @@ -76,10 +87,8 @@ describe("Settings", () => {
});

test("should get the setting by key", async () => {
const toBeSucceeded = await consumptionServices.settings.createSetting({
key: "a-key",
value: { key: ["value"] }
});
const value = { aKey: "a-value" };
const toBeSucceeded = await consumptionServices.settings.createSetting({ key: "a-key", value });

await consumptionServices.settings.createSetting({
key: "a-key",
Expand All @@ -94,6 +103,37 @@ describe("Settings", () => {
const setting = result.value;
expect(setting.value).toStrictEqual({ key: ["newValue"] });
});

test("should upsert a setting by key when it does not exist yet", async () => {
await consumptionServices.settings.upsertSettingByKey({
key: "a-key",
value: { aKey: "a-value" }
});

const result = await consumptionServices.settings.getSettings({});
expect(result).toBeSuccessful();
expect(result.value).toHaveLength(1);

const setting = await consumptionServices.settings.getSettingByKey({ key: "a-key" });
expect(setting.value.value).toStrictEqual({ aKey: "a-value" });
});

test("should upsert a setting by key", async () => {
const value = { aKey: "a-value" };
await consumptionServices.settings.createSetting({ key: "a-key", value });

await consumptionServices.settings.upsertSettingByKey({
key: "a-key",
value: { aKey: "aNewValue" }
});

const result = await consumptionServices.settings.getSettings({});
expect(result).toBeSuccessful();
expect(result.value).toHaveLength(1);

const setting = await consumptionServices.settings.getSettingByKey({ key: "a-key" });
expect(setting.value.value).toStrictEqual({ aKey: "aNewValue" });
});
});

describe("Settings query", () => {
Expand Down

0 comments on commit 00d2bba

Please sign in to comment.