Skip to content
This repository has been archived by the owner on Aug 15, 2021. It is now read-only.

Commit

Permalink
Separate out agent and room models
Browse files Browse the repository at this point in the history
Use parent id to associate child with parent as one to many relationship
This way we dont have to maintain child list with parent and a parent's
children can be found by simple find query

Closes #39
Related #34
  • Loading branch information
nickdex committed Feb 27, 2019
1 parent e0543dc commit fe934a7
Show file tree
Hide file tree
Showing 10 changed files with 168 additions and 53 deletions.
6 changes: 6 additions & 0 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ import { PushController } from './controllers/push';

// Hooks
import { clientHooks } from './client-device/client-hook';
import { iotAgentHooks } from './iot-agent/iot-agent-hook';
import { iotDeviceHooks } from './iot-device/iot-device-hook';
import { roomHooks } from './room/room-hook';

// Database
import { databaseService } from './database';
Expand Down Expand Up @@ -59,10 +61,14 @@ app.use('/clients', databaseService('users'));
app.use('/users', databaseService('users'));

app.use('/devices', databaseService('devices'));
app.use('/agents', databaseService('agents'));
app.use('/rooms', databaseService('rooms'));
app.use('/groups', databaseService('groups'));

app.service('clients').hooks(clientHooks);
app.service('devices').hooks(iotDeviceHooks);
app.service('agents').hooks(iotAgentHooks);
app.service('rooms').hooks(roomHooks);
logger.verbose('Service initialization complete');
// #endregion

Expand Down
7 changes: 4 additions & 3 deletions src/device-group/device-group-model.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { IIotRoom } from '../room/iot-room-model';
import { IRoom } from '../room/room-model';

export interface IDeviceGroup {
_id: string; // join([IUser._id, name], '-')
name: string;
ownerId: string;
userIds: string[];

rooms: IIotRoom[];
userIds: string[]; // IUser._id

rooms?: IRoom[];
}
42 changes: 42 additions & 0 deletions src/iot-agent/iot-agent-hook.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { HookContext, HooksObject } from '@feathersjs/feathers';

import { logger } from '../logger';
import { Utility } from '../utility';

import { IRoom } from '../room/room-model';
import { IIotAgent } from './iot-agent-model';

export const iotAgentHooks: Partial<HooksObject> = {
before: {
async create(context: HookContext<IIotAgent>) {
const data = context.data;
const params = context.params;
const { roomId }: { roomId: string } = <any>params.query;

const room: IRoom = await context.app.service('rooms').get(roomId);
const agentId = Utility.generateId(roomId, data.site);

// #region Validation
if (room === undefined) {
const message =
'Given device group does not exist. Try different group or create one';
logger.warn(message, { device: data, room });
throw new Error(message);
}

if (await Utility.isChild(agentId, context.service, { roomId })) {
const message = 'Agent already exists for given room';
logger.warn(message, { device: data, room });
throw new Error(message);
}
// #endregion

// Add reverse reference
data.roomId = roomId;

data._id = agentId;

return context;
}
}
};
10 changes: 10 additions & 0 deletions src/iot-agent/iot-agent-model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { IIotDevice } from '../iot-device/iot-device-model';

export interface IIotAgent {
_id: string; // join([IRoom._id, site], '-') | Also used for channel
site: string;

roomId: string; // IRoom._id

devices?: IIotDevice[];
}
57 changes: 18 additions & 39 deletions src/iot-device/iot-device-hook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import * as lodash from 'lodash';

import { Mqtt } from '../iot/mqtt';
import { logger } from '../logger';
import { Utility } from '../utility';

import { IDeviceGroup } from '../device-group/device-group-model';
import { IIotAgent } from '../iot-agent/iot-agent-model';
import { IIotDevice } from './iot-device-model';

export const iotDeviceHooks: Partial<HooksObject> = {
Expand Down Expand Up @@ -76,55 +77,33 @@ export const iotDeviceHooks: Partial<HooksObject> = {
async create(context: HookContext<IIotDevice>) {
const data = context.data;
const params = context.params;
const {
roomId,
deviceGroupId
}: { roomId: string; deviceGroupId: string } = <any>params.query;
const { agentId }: { agentId: string } = <any>params.query;

// Default state when creating
data.isOn = false;

const deviceGroup: IDeviceGroup = await context.app
.service('groups')
.get(deviceGroupId);
const agent: IIotAgent = await context.app.service('agents').get(agentId);
const deviceId = Utility.generateId(agentId, data.name);

const room = lodash.find(deviceGroup.rooms, { _id: roomId });

// #region Parameter checking
if (room === undefined) {
if (agent === undefined) {
const message =
'room does not exist. Please check room id or create new room';
logger.warn(message, params.query);
'Given agent does not exist. Try different agent or create one';
logger.warn(message, { device: data, agentId });
throw new Error(message);
}

const deviceId = lodash
.join([deviceGroupId, roomId, data.name], '-')
.toLowerCase();

if (lodash.includes(room.deviceIds, deviceId)) {
const message = 'Device already exists in the given room';
logger.warn(message, { device: data, room: roomId });
if (
await Utility.isChild(deviceId, context.service, { agentId })
) {
const message = 'Device already exist for given agent';
logger.warn(message, { data });
throw new Error(message);
}
// #endregion

// Add Room and Group Reference
data.roomId = roomId;
data.groupId = deviceGroupId;
// Add Device Reference
room.deviceIds.push(deviceId);
// For Updating group in after hook when successfully saved
params.deviceGroup = deviceGroup;

return context;
}
},
after: {
async create(context: HookContext<IIotDevice>) {
const deviceGroup: IDeviceGroup = context.params.deviceGroup;
// Default state when creating
data.isOn = false;
// Add Agent reverse reference
data.agentId = agent._id;

await context.app.service('groups').patch(deviceGroup._id, deviceGroup);
data._id = deviceId;

return context;
}
Expand Down
6 changes: 3 additions & 3 deletions src/iot-device/iot-device-model.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
export interface IIotDevice {
_id: string; // join([IDeviceGroup._id, IIotRoom._id, name], '-')
_id: string; // join([IIotAgent._id, name], '-')
name: string;
pin: number;
isOn: boolean;
roomId: string;
groupId: string;

agentId: string; // IIotAgent._id
}
8 changes: 0 additions & 8 deletions src/room/iot-room-model.ts

This file was deleted.

46 changes: 46 additions & 0 deletions src/room/room-hook.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { HookContext, HooksObject } from '@feathersjs/feathers';

import { logger } from '../logger';
import { Utility } from '../utility';

import { IDeviceGroup } from '../device-group/device-group-model';
import { IRoom } from './room-model';

export const roomHooks: Partial<HooksObject> = {
before: {
async create(context: HookContext<IRoom>) {
const data = context.data;
const params = context.params;
const { deviceGroupId }: { deviceGroupId: string } = <any>params.query;

const deviceGroup: IDeviceGroup = await context.app
.service('groups')
.get(deviceGroupId);
const roomId = Utility.generateId(deviceGroupId, data.name);

//#region Validation
if (deviceGroup === undefined) {
const message =
'Given device group does not exist. Try different group or create one';
logger.warn(message, { device: data, deviceGroupId });
throw new Error(message);
}

if (
await Utility.isChild(roomId, context.service, { deviceGroupId })
) {
const message = 'Room already exists for given device group';
logger.warn(message, { data });
throw new Error(message);
}
// #endregion

// Add reverse reference
data.deviceGroupId = deviceGroupId;

data._id = roomId;

return context;
}
}
};
10 changes: 10 additions & 0 deletions src/room/room-model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { IIotAgent } from '../iot-agent/iot-agent-model';

export interface IRoom {
_id: string; // join([IDeviceGroup._id, name], '-')
name: string;

deviceGroupId: string; // IDeviceGroup._id

agents?: IIotAgent[];
}
29 changes: 29 additions & 0 deletions src/utility.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,34 @@
import { Service } from '@feathersjs/feathers';
import * as lodash from 'lodash';

export namespace Utility {
export const equalsIgnoreCase = (string1: string, string2: string) => {
return string1.toUpperCase() === string2.toUpperCase();
};

export const findIdsWhere = (service: Service<any>, parentIdKvPair) =>
service.find({
query: { $select: ['_id'], ...parentIdKvPair }
});

export const includes = async (id: string, ids: string[]) => {
return (
!(lodash.isNil(ids) || lodash.isEmpty(ids)) && lodash.includes(ids, id)
);
};

export const isChild = async (childId, childStore, parentIdKvPair) => {
return includes(childId, await findIdsWhere(childStore, parentIdKvPair));
};

export const generateId = (parentId, param) => {
const updatedId = lodash
.chain(param)
.map(char => lodash.toLower(char))
.filter(char => char >= 'a' && char <= 'z')
.join('')
.value();

return lodash.join([parentId, updatedId], '-');
};
}

0 comments on commit fe934a7

Please sign in to comment.