Skip to content

Commit

Permalink
[Issue #204] Only create 1 FeatureOfInterest per Thing (#216)
Browse files Browse the repository at this point in the history
  • Loading branch information
albertopq authored Jan 17, 2017
1 parent c9ad9de commit 4a10133
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 12 deletions.
69 changes: 58 additions & 11 deletions src/models/association.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
featuresOfInterest,
iotId,
locations,
observations,
observedProperties,
sensors,
things
Expand All @@ -32,17 +33,24 @@ import {
/*
* Converts a Location into a FeatureOfInterest
*/
const featureOfInterestFromLocation = location => {
if (!location) {
const featureOfInterestFromLocation = locationObject => {
if (!locationObject) {
return null;
}

const options = locationObject.$modelOptions && locationObject.$modelOptions;
if (options && options.name.plural === featuresOfInterest) {
return {
'@iot.id': locationObject.id
};
}

const location = locationObject.dataValues || locationObject;
const feature = Object.assign({}, {
name: location.name,
description: location.description,
encodingType: location.encodingType
});

feature.feature = Object.assign({}, location.location);
Reflect.deleteProperty(feature, 'location');
return feature;
Expand Down Expand Up @@ -358,19 +366,35 @@ const maybeCreate = (transaction, instance, req, exclude, thingLocation) => {
});
}

const sameLocation = (loc1, loc2) => {
if (!loc1 || !loc2) {
return false;
}
return JSON.stringify(loc1) === JSON.stringify(loc2);
}

const getLocationFromDatastream = (datastreamEntity) => {
return db().then(models => {
const includeDatastreamsAndLocations = [
models[locations], {
model: models[datastreams],
include: {
model: models[observations],
include: [models[featuresOfInterest]]
}
}
];
if (datastreamEntity[iotId]) {
return findLocation(datastreams, datastreamEntity[iotId], {
model: models[things],
include: models[locations]
include: includeDatastreamsAndLocations
});
}

if (datastreamEntity.Thing) {
if (datastreamEntity.Thing[iotId]) {
return findLocation(things, datastreamEntity.Thing[iotId],
models[locations]);
includeDatastreamsAndLocations);
}

if (datastreamEntity.Thing.Locations) {
Expand All @@ -387,31 +411,54 @@ const getLocationFromDatastream = (datastreamEntity) => {
});
}


const findLocation = (modelName, id, include = []) => {
return db().then(models => {
return models[modelName].findOne({
where: { id: id },
include: include
}).then(instance => {
let _currentThing, loc;
try {
let _currentLoc;
switch (modelName) {
case datastreams:
_currentLoc = instance.Thing.Locations[0];
_currentThing = instance.Thing;
loc = _currentThing.Locations[0];
break;
case things:
_currentLoc = instance.Locations[0];
_currentThing = instance;
loc = instance.Locations[0];
break;
case locations:
_currentLoc = instance;
loc = instance;
break;
default:
break;
}
return _currentLoc.dataValues;
} catch(e) {
return null;
loc = null;
}

if (!_currentThing) {
return loc;
}

// We need to check if for any of the Datastreams of that Thing,
// already exists an Observation which FeatureOfInterest matches
// the last location of the Thing.
const thingDatastreams = _currentThing.Datastreams || [];
for (let i = 0; i < thingDatastreams.length; i++) {
const currentDatastream = thingDatastreams[i];
for (let j = 0; j < currentDatastream.Observations.length; j++) {
const currentObservation = currentDatastream.Observations[j];
const foi = currentObservation.FeatureOfInterest;
if (sameLocation(foi && foi.feature, loc && loc.location)) {
return foi;
}
}
}

return loc;
});
});
}
Expand Down
4 changes: 3 additions & 1 deletion test/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,9 @@ module.exports = (endpoint, port, mandatory, optional = []) => {
res.header.location.should.be.equal(fullPrepath + path);
const expectedModels = Object.keys(expected);
Promise.all(expectedModels.map(name => {
return models[name].findAndCountAll().then(result => {
return models[name].findAndCountAll({
order: 'id desc'
}).then(result => {
const resultObject = {};
resultObject[name] = result;
return Promise.resolve(resultObject);
Expand Down
33 changes: 33 additions & 0 deletions test/test_observations.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,39 @@ commonTests(observations, 8885, mandatory, optional).then(tester => {
});
});

describe('More than one Observation without FeatureOfInterest', () => {
let body, countObject;
beforeEach(done => {
db().then(models => {
const datastreamEntity = Object.assign({}, DatastreamsEntity);
datastreamEntity.Thing.Locations = LocationsEntity;
models[datastreams].create(datastreamEntity, {
include: {
model: models.Things, include: { model: models.Locations }
}
}).then(relation => {
body = Object.assign({}, ObservationsEntity);
body.Datastream = {
'@iot.id': relation.id
};
Reflect.deleteProperty(body, featureOfInterest);
countObject = {
'Observations': { count: 1 },
'Datastreams': { count: 1 },
'FeaturesOfInterest': { count: 1 }
};
tester.postSuccess(done, body, countObject);
});
});
});

it('should create only 1 FeatureOfInterest for a Datastream with ' +
'Observations and a linked FeatureOfInterest', done => {
countObject.Observations.count++;
tester.postSuccess(done, body, countObject);
});
});

it('should return 201 when linking a Datastream entity with a linked ' +
'Thing', done => {
db().then(models => {
Expand Down

0 comments on commit 4a10133

Please sign in to comment.