Skip to content

Commit 9ce7c7e

Browse files
Merge pull request #428 from kuzzleio/KZLPRD-979-group-affinity
feat(group):Allow devices group and add groupModel affinity
2 parents 3b48a18 + 1a81b91 commit 9ce7c7e

File tree

25 files changed

+1113
-137
lines changed

25 files changed

+1113
-137
lines changed

lib/modules/asset/types/AssetContent.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export interface AssetContent<
3232
measureNames: Array<{ asset: string; device: string; type: string }>;
3333
}>;
3434
/**
35-
* Id's of asset groups
35+
* Path's of asset groups
3636
*/
3737
groups: Array<{
3838
path: string;

lib/modules/decoder/PayloadService.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@ export class PayloadService extends BaseService {
321321
const body: DeviceContent = {
322322
assetId: null,
323323
engineId: null,
324+
groups: [],
324325
lastMeasuredAt: 0,
325326
measureSlots: deviceModelContent.device.measures,
326327
measures: {},

lib/modules/device/DeviceService.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ export class DeviceService extends DigitalTwinService {
110110
_source: {
111111
assetId: null,
112112
engineId: null,
113+
groups: [],
113114
lastMeasuredAt: 0,
114115
measureSlots: [],
115116
measures: {},

lib/modules/device/collections/deviceMappings.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,15 @@ export const devicesMappings: CollectionMappings = {
1212
type: "keyword",
1313
fields: { text: { type: "text" } },
1414
},
15+
groups: {
16+
properties: {
17+
path: {
18+
type: "keyword",
19+
fields: { text: { type: "text" } },
20+
},
21+
date: { type: "date" },
22+
},
23+
},
1524
reference: {
1625
type: "keyword",
1726
fields: { text: { type: "text" } },

lib/modules/device/types/DeviceContent.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,11 @@ export interface DeviceContent<
1717
/**
1818
*/
1919
engineId: string;
20+
/**
21+
* Path's of device's groups
22+
*/
23+
groups: Array<{
24+
path: string;
25+
date: number;
26+
}>;
2027
}

lib/modules/group/GroupsController.ts

Lines changed: 118 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,26 @@ import { DeviceManagerPlugin, InternalCollection } from "../plugin";
1212
import {
1313
ApiGroupAddAssetsRequest,
1414
ApiGroupAddAssetsResult,
15+
ApiGroupAddDeviceRequest,
16+
ApiGroupAddDevicesResult,
1517
ApiGroupCreateRequest,
1618
ApiGroupCreateResult,
1719
ApiGroupDeleteResult,
1820
ApiGroupGetResult,
21+
ApiGroupListItemsResult,
22+
ApiGroupRemoveAssetsRequest,
1923
ApiGroupRemoveAssetsResult,
24+
ApiGroupRemoveDeviceRequest,
25+
ApiGroupRemoveDeviceResult,
2026
ApiGroupSearchResult,
2127
ApiGroupUpdateResult,
2228
GroupsBodyRequest,
2329
} from "./types/GroupsApi";
24-
import { GroupContent, GroupsBody } from "./types/GroupContent";
30+
import { GroupContent } from "./types/GroupContent";
2531
import { AssetContent } from "../asset";
2632
import { GroupsService } from "./GroupsService";
2733
import { AskModelGroupGet } from "../model";
34+
import { DeviceContent } from "../device";
2835

2936
export class GroupsController {
3037
definition: ControllerDefinition;
@@ -88,11 +95,38 @@ export class GroupsController {
8895
handler: this.removeAsset.bind(this),
8996
http: [
9097
{
91-
path: "device-manager/:engineId/groups/:_id/removeAsset",
98+
path: "device-manager/:engineId/groups/removeAsset",
9299
verb: "post",
93100
},
94101
],
95102
},
103+
addDevice: {
104+
handler: this.addDevice.bind(this),
105+
http: [
106+
{
107+
path: "device-manager/:engineId/groups/addDevice",
108+
verb: "post",
109+
},
110+
],
111+
},
112+
removeDevice: {
113+
handler: this.removeDevice.bind(this),
114+
http: [
115+
{
116+
path: "device-manager/:engineId/groups/removeDevice",
117+
verb: "post",
118+
},
119+
],
120+
},
121+
listItems: {
122+
handler: this.listItems.bind(this),
123+
http: [
124+
{
125+
path: "device-manager/:engineId/groups/:_id/listItems",
126+
verb: "get",
127+
},
128+
],
129+
},
96130
},
97131
};
98132
/* eslint-enable sort-keys */
@@ -299,34 +333,65 @@ export class GroupsController {
299333
InternalCollection.ASSETS,
300334
{
301335
query: {
302-
regexp: {
336+
prefix: {
303337
"groups.path": {
304-
value: `${groupToUpdate._source.path}.*`,
338+
value: groupToUpdate._source.path,
339+
},
340+
},
341+
},
342+
},
343+
{ lang: "koncorde" },
344+
);
345+
const { hits: devices } = await this.sdk.document.search<DeviceContent>(
346+
engineId,
347+
InternalCollection.DEVICES,
348+
{
349+
query: {
350+
prefix: {
351+
"groups.path": {
352+
value: groupToUpdate._source.path,
305353
},
306354
},
307355
},
308356
},
309357
{ lang: "koncorde" },
310358
);
311-
312359
await this.sdk.document.mUpdate(
313360
engineId,
314361
InternalCollection.ASSETS,
315362
assets.map((asset) => ({
316363
_id: asset._id,
317364
body: {
318-
groups: asset._source.groups
319-
.filter((grp) => grp.path !== groupToUpdate._source.path)
320-
.map((grp) => {
321-
if (grp.path.includes(groupToUpdate._source.path)) {
322-
grp.path = grp.path.replace(
323-
groupToUpdate._source.path,
324-
updatedGroup._source.path,
325-
);
326-
grp.date = Date.now();
327-
}
328-
return grp;
329-
}),
365+
groups: asset._source.groups.map((grp) => {
366+
if (grp.path.includes(groupToUpdate._source.path)) {
367+
grp.path = grp.path.replace(
368+
groupToUpdate._source.path,
369+
updatedGroup._source.path,
370+
);
371+
grp.date = Date.now();
372+
}
373+
return grp;
374+
}),
375+
},
376+
})),
377+
{ strict: true },
378+
);
379+
await this.sdk.document.mUpdate(
380+
engineId,
381+
InternalCollection.DEVICES,
382+
devices.map((device) => ({
383+
_id: device._id,
384+
body: {
385+
groups: device._source.groups.map((grp) => {
386+
if (grp.path.includes(groupToUpdate._source.path)) {
387+
grp.path = grp.path.replace(
388+
groupToUpdate._source.path,
389+
updatedGroup._source.path,
390+
);
391+
grp.date = Date.now();
392+
}
393+
return grp;
394+
}),
330395
},
331396
})),
332397
{ strict: true },
@@ -339,9 +404,9 @@ export class GroupsController {
339404
query: {
340405
and: [
341406
{
342-
regexp: {
407+
prefix: {
343408
path: {
344-
value: `${groupToUpdate._source.path}.*`,
409+
value: groupToUpdate._source.path,
345410
},
346411
},
347412
},
@@ -383,6 +448,21 @@ export class GroupsController {
383448
return this.groupsService.search(engineId, searchParams, request);
384449
}
385450

451+
async listItems(request: KuzzleRequest): Promise<ApiGroupListItemsResult> {
452+
const engineId = request.getString("engineId");
453+
const _id = request.getId();
454+
const includeChildren = request.getBodyBoolean("includeChildren");
455+
const searchParams = request.getSearchParams();
456+
const { from, size } = searchParams;
457+
return this.groupsService.listItems(
458+
engineId,
459+
_id,
460+
includeChildren,
461+
{ from, size },
462+
request,
463+
);
464+
}
465+
386466
async addAsset(request: KuzzleRequest): Promise<ApiGroupAddAssetsResult> {
387467
const engineId = request.getString("engineId");
388468
const body = request.getBody() as ApiGroupAddAssetsRequest["body"];
@@ -396,58 +476,30 @@ export class GroupsController {
396476
request: KuzzleRequest,
397477
): Promise<ApiGroupRemoveAssetsResult> {
398478
const engineId = request.getString("engineId");
399-
const body = request.getBody() as ApiGroupAddAssetsRequest["body"];
479+
const body = request.getBody() as ApiGroupRemoveAssetsRequest["body"];
400480
const path = request.getBodyString("path");
401481
const assetIds = body.assetIds;
402482
this.checkPath(engineId, path);
403483
return this.groupsService.removeAsset(engineId, path, assetIds, request);
484+
}
404485

405-
// ? Get document to check if really exists, even if not indexed
406-
407-
const assets = [];
408-
for (const assetId of body.assetIds) {
409-
const assetContent = (
410-
await this.sdk.document.get<AssetContent>(
411-
engineId,
412-
InternalCollection.ASSETS,
413-
assetId,
414-
)
415-
)._source;
416-
417-
if (!Array.isArray(assetContent.groups)) {
418-
continue;
419-
}
420-
421-
assetContent.groups = assetContent.groups.filter(
422-
(group) => group.path !== path,
423-
);
424-
425-
assets.push({
426-
_id: assetId,
427-
body: assetContent,
428-
});
429-
}
430-
431-
const groupsUpdate = await this.as(
432-
request.getUser(),
433-
).document.update<GroupsBody>(
434-
engineId,
435-
InternalCollection.GROUPS,
436-
path.split(".").pop(),
437-
{
438-
lastUpdate: Date.now(),
439-
},
440-
{ source: true },
441-
);
486+
async addDevice(request: KuzzleRequest): Promise<ApiGroupAddDevicesResult> {
487+
const engineId = request.getString("engineId");
488+
const body = request.getBody() as ApiGroupAddDeviceRequest["body"];
489+
const path = request.getBodyString("path");
490+
const deviceIds = body.deviceIds;
491+
this.checkPath(engineId, path);
492+
return this.groupsService.addDevice(engineId, path, deviceIds, request);
493+
}
442494

443-
const update = await this.sdk.document.mUpdate(
444-
engineId,
445-
InternalCollection.ASSETS,
446-
assets,
447-
);
448-
return {
449-
...update,
450-
group: groupsUpdate,
451-
};
495+
async removeDevice(
496+
request: KuzzleRequest,
497+
): Promise<ApiGroupRemoveDeviceResult> {
498+
const engineId = request.getString("engineId");
499+
const body = request.getBody() as ApiGroupRemoveDeviceRequest["body"];
500+
const path = request.getBodyString("path");
501+
const deviceIds = body.deviceIds;
502+
this.checkPath(engineId, path);
503+
return this.groupsService.removeDevice(engineId, path, deviceIds, request);
452504
}
453505
}

0 commit comments

Comments
 (0)