Skip to content

Commit

Permalink
feat: update embedded measure slots when updating models
Browse files Browse the repository at this point in the history
  • Loading branch information
Kuruyia authored and sebtiz13 committed Nov 12, 2024
1 parent 44a56bc commit b428785
Show file tree
Hide file tree
Showing 7 changed files with 368 additions and 15 deletions.
2 changes: 2 additions & 0 deletions lib/modules/asset/AssetService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,8 @@ export class AssetService extends DigitalTwinService {
...assetMetadata,
};

asset._source.measureSlots = assetModel.asset.measures;

acc[asset.index].push(asset as KDocument<AssetContent>);

return acc;
Expand Down
81 changes: 79 additions & 2 deletions lib/modules/device/DeviceService.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { BadRequestError, KuzzleRequest } from "kuzzle";
import { ask, onAsk } from "kuzzle-plugin-commons";
import { JSONObject, KDocument, KHit, SearchResult } from "kuzzle-sdk";
import {
BaseRequest,
DocumentSearchResult,
JSONObject,
KDocument,
KHit,
SearchResult,
} from "kuzzle-sdk";

import { DecodedMeasurement } from "../measure";
import {
Expand All @@ -9,7 +16,11 @@ import {
AssetModelContent,
DeviceModelContent,
} from "../model";
import { DeviceManagerPlugin, InternalCollection } from "../plugin";
import {
AskEngineList,
DeviceManagerPlugin,
InternalCollection,
} from "../plugin";
import { DigitalTwinService, Metadata, SearchParams, lock } from "../shared";
import {
AskAssetHistoryAdd,
Expand All @@ -26,6 +37,7 @@ import {
AskDeviceAttachEngine,
AskDeviceDetachEngine,
AskDeviceLinkAsset,
AskDeviceRefreshModel,
AskDeviceUnlinkAsset,
EventDeviceUpdateAfter,
EventDeviceUpdateBefore,
Expand Down Expand Up @@ -80,6 +92,11 @@ export class DeviceService extends DigitalTwinService {
await this.attachEngine(engineId, deviceId, request);
},
);

onAsk<AskDeviceRefreshModel>(
"ask:device-manager:device:refresh-model",
this.refreshModel.bind(this),
);
}

/**
Expand Down Expand Up @@ -936,4 +953,64 @@ export class DeviceService extends DigitalTwinService {
model,
});
}

private async refreshModel({
deviceModel,
}: {
deviceModel: DeviceModelContent;
}): Promise<void> {
const engines = await ask<AskEngineList>("ask:device-manager:engine:list", {
group: null,
});

const targets = engines.map((engine) => ({
collections: [InternalCollection.DEVICES],
index: engine.index,
}));

const devices = await this.sdk.query<
BaseRequest,
DocumentSearchResult<DeviceContent>
>({
action: "search",
body: { query: { equals: { model: deviceModel.device.model } } },
controller: "document",
lang: "koncorde",
targets,
});

const updatedDevicesPerIndex: Record<string, KDocument<DeviceContent>[]> =
devices.result.hits.reduce(
(
acc: Record<string, KDocument<DeviceContent>[]>,
device: JSONObject,
) => {
device._source.measureSlots = deviceModel.device.measures;

acc[device.index].push(device as KDocument<DeviceContent>);

return acc;
},
Object.fromEntries(
engines.map((engine) => [
engine.index,
[] as KDocument<DeviceContent>[],
]),
),
);

await Promise.all(
Object.entries(updatedDevicesPerIndex).map(([index, updatedDevices]) =>
this.sdk.document.mReplace<DeviceContent>(
index,
InternalCollection.DEVICES,
updatedDevices.map((device) => ({
_id: device._id,
body: device._source,
})),
{ refresh: "wait_for" },
),
),
);
}
}
11 changes: 11 additions & 0 deletions lib/modules/device/types/DeviceEvents.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { User } from "kuzzle";
import { KDocument } from "kuzzle-sdk";

import { DeviceModelContent } from "../../../modules/model";
import { Metadata } from "../../../modules/shared";

import { DeviceContent } from "./DeviceContent";
Expand Down Expand Up @@ -68,3 +69,13 @@ export type AskDeviceAttachEngine = {

result: void;
};

export type AskDeviceRefreshModel = {
name: "ask:device-manager:device:refresh-model";

payload: {
deviceModel: DeviceModelContent;
};

result: void;
};
30 changes: 22 additions & 8 deletions lib/modules/model/ModelService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import { MeasureValuesDetails } from "../measure";
import { NamedMeasures } from "../decoder";
import { getNamedMeasuresDuplicates } from "./MeasuresDuplicates";
import { MeasuresNamesDuplicatesError } from "./MeasuresNamesDuplicatesError";
import { AskDeviceRefreshModel } from "../device";

export class ModelService extends BaseService {
constructor(plugin: DeviceManagerPlugin) {
Expand Down Expand Up @@ -361,6 +362,13 @@ export class ModelService extends BaseService {
);
await ask<AskEngineUpdateAll>("ask:device-manager:engine:updateAll");

await ask<AskDeviceRefreshModel>(
"ask:device-manager:device:refresh-model",
{
deviceModel: modelContent,
},
);

return deviceModel;
}

Expand Down Expand Up @@ -746,15 +754,21 @@ export class ModelService extends BaseService {
{ source: true },
);

await this.sdk.collection.refresh(
this.config.adminIndex,
InternalCollection.MODELS,
);
await ask<AskEngineUpdateAll>("ask:device-manager:engine:updateAll");
// ? Only update engines and refresh asset models when necessary
if (Object.keys(metadataMappings).length > 0 || measures.length > 0) {
await this.sdk.collection.refresh(
this.config.adminIndex,
InternalCollection.MODELS,
);

await ask<AskAssetRefreshModel>("ask:device-manager:asset:refresh-model", {
assetModel: assetModelContent,
});
await ask<AskEngineUpdateAll>("ask:device-manager:engine:updateAll");
await ask<AskAssetRefreshModel>(
"ask:device-manager:asset:refresh-model",
{
assetModel: endDocument._source,
},
);
}

return endDocument;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import {
ApiAssetCreateRequest,
ApiAssetCreateResult,
} from "../../../../lib/modules/asset";
import {
ApiModelUpdateAssetRequest,
ApiModelUpdateAssetResult,
ApiModelWriteAssetRequest,
ApiModelWriteAssetResult,
} from "../../../../lib/modules/model";
import { setupHooks } from "../../../helpers";

jest.setTimeout(10000);

describe("Asset model measure slots propagation", () => {
const sdk = setupHooks();

it("should update the embedded measure slots of existing assets with writeAsset", async () => {
await sdk.query<ApiModelWriteAssetRequest, ApiModelWriteAssetResult>({
controller: "device-manager/models",
action: "writeAsset",
body: {
engineGroup: "commons",
model: "Plane",
metadataMappings: { size: { type: "integer" } },
measures: [{ name: "temperatureExt", type: "temperature" }],
},
});

const { result } = await sdk.query<
ApiAssetCreateRequest,
ApiAssetCreateResult
>({
controller: "device-manager/assets",
action: "create",
engineId: "engine-kuzzle",
body: {
model: "Plane",
reference: "Technoplane",
metadata: { size: 8311 },
},
});

expect(result).toMatchObject({
_source: {
measureSlots: [
{
name: "temperatureExt",
type: "temperature",
},
],
},
});

await sdk.query<ApiModelWriteAssetRequest, ApiModelWriteAssetResult>({
controller: "device-manager/models",
action: "writeAsset",
body: {
engineGroup: "commons",
model: "Plane",
metadataMappings: { size: { type: "integer" } },
measures: [
{
name: "temperatureExt",
type: "temperature",
},
{
name: "temperatureInt",
type: "temperature",
},
],
},
});

await expect(
sdk.document.get("engine-kuzzle", "assets", "Plane-Technoplane"),
).resolves.toMatchObject({
_source: {
measureSlots: [
{
name: "temperatureExt",
type: "temperature",
},
{
name: "temperatureInt",
type: "temperature",
},
],
},
});
});

it("should update the embedded measure slots of existing assets with updateAsset", async () => {
await sdk.query<ApiModelWriteAssetRequest, ApiModelWriteAssetResult>({
controller: "device-manager/models",
action: "writeAsset",
body: {
engineGroup: "commons",
model: "Plane",
metadataMappings: { size: { type: "integer" } },
measures: [{ name: "temperatureExt", type: "temperature" }],
},
});

const { result } = await sdk.query<
ApiAssetCreateRequest,
ApiAssetCreateResult
>({
controller: "device-manager/assets",
action: "create",
engineId: "engine-kuzzle",
body: {
model: "Plane",
reference: "Technoplane",
metadata: { size: 8311 },
},
});

expect(result).toMatchObject({
_source: {
measureSlots: [
{
name: "temperatureExt",
type: "temperature",
},
],
},
});

await sdk.query<ApiModelUpdateAssetRequest, ApiModelUpdateAssetResult>({
controller: "device-manager/models",
action: "updateAsset",
engineGroup: "commons",
model: "Plane",
body: {
measures: [
{
name: "temperatureExt",
type: "temperature",
},
{
name: "temperatureInt",
type: "temperature",
},
],
},
});

await expect(
sdk.document.get("engine-kuzzle", "assets", "Plane-Technoplane"),
).resolves.toMatchObject({
_source: {
measureSlots: [
{
name: "temperatureExt",
type: "temperature",
},
{
name: "temperatureInt",
type: "temperature",
},
],
},
});
});
});
5 changes: 0 additions & 5 deletions tests/scenario/modules/models/asset-model.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -385,11 +385,6 @@ describe("ModelsController:assets", () => {
engineGroup: "commons",
model: "AdvancedWarehouse",
body: {
metadataMappings: {
location: { type: "geo_point" },
floor: { type: "integer" },
},
measures: [{ name: "temperatureInt", type: "temperature" }],
tooltipModels: updatedTooltipModels,
},
});
Expand Down
Loading

0 comments on commit b428785

Please sign in to comment.