Skip to content

Commit a05420b

Browse files
authored
Update mongoose to latest v5 (#813)
* Update mongoose to latest v5 * Update validator for sensors array in box schema * Update ttnSchema validator * return new box * return newly created device * tweak before hook * Clean up tests
1 parent 7c65fe1 commit a05420b

File tree

6 files changed

+283
-238
lines changed

6 files changed

+283
-238
lines changed

packages/models/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"jsonpath": "^1.1.1",
1818
"lodash.isequal": "^4.5.0",
1919
"moment": "^2.29.4",
20-
"mongoose": "^4.13.21",
20+
"mongoose": "^5.13.20",
2121
"mongoose-timestamp": "^0.6",
2222
"pino": "^8.8.0",
2323
"uuid": "^8.3.2"

packages/models/src/box/box.js

+102-84
Original file line numberDiff line numberDiff line change
@@ -44,95 +44,113 @@ const locationSchema = new Schema({
4444
});
4545

4646
//senseBox schema
47-
const boxSchema = new Schema({
48-
name: {
49-
type: String,
50-
required: true,
51-
trim: true
52-
},
53-
locations: {
54-
type: [locationSchema],
55-
required: true,
56-
},
57-
currentLocation: {
58-
type: locationSchema,
59-
required: true,
60-
},
61-
exposure: {
62-
type: String,
63-
trim: true,
64-
required: true,
65-
enum: ['unknown', 'indoor', 'outdoor', 'mobile']
66-
},
67-
grouptag: {
68-
type: [String], // Default value for array is [] (empty array)
69-
trim: true,
70-
required: false
71-
},
72-
model: {
73-
type: String,
74-
required: true,
75-
trim: true,
76-
default: 'custom',
77-
enum: ['custom', ...sensorLayouts.models]
78-
},
79-
weblink: {
80-
type: String,
81-
trim: true,
82-
required: false
83-
},
84-
description: {
85-
type: String,
86-
trim: true,
87-
required: false
88-
},
89-
image: {
90-
type: String,
91-
trim: true,
92-
required: false,
93-
/* eslint-disable func-name-matching */
94-
set: function imageSetter ({ type, data, deleteImage }) {
95-
/* eslint-enable func-name-matching */
96-
if (type && data) {
97-
const filename = `${this._id}_${Math.round(Date.now() / 1000).toString(36)}.${type}`;
98-
try {
99-
fs.writeFileSync(`${imageFolder}${filename}`, data);
100-
} catch (err) {
101-
log.warn(err);
102-
103-
return;
104-
}
47+
const boxSchema = new Schema(
48+
{
49+
name: {
50+
type: String,
51+
required: true,
52+
trim: true
53+
},
54+
locations: {
55+
type: [locationSchema],
56+
required: true
57+
},
58+
currentLocation: {
59+
type: locationSchema,
60+
required: true
61+
},
62+
exposure: {
63+
type: String,
64+
trim: true,
65+
required: true,
66+
enum: ['unknown', 'indoor', 'outdoor', 'mobile']
67+
},
68+
grouptag: {
69+
type: [String], // Default value for array is [] (empty array)
70+
trim: true,
71+
required: false
72+
},
73+
model: {
74+
type: String,
75+
required: true,
76+
trim: true,
77+
default: 'custom',
78+
enum: ['custom', ...sensorLayouts.models]
79+
},
80+
weblink: {
81+
type: String,
82+
trim: true,
83+
required: false
84+
},
85+
description: {
86+
type: String,
87+
trim: true,
88+
required: false
89+
},
90+
image: {
91+
type: String,
92+
trim: true,
93+
required: false,
94+
/* eslint-disable func-name-matching */
95+
set: function imageSetter ({ type, data, deleteImage }) {
96+
/* eslint-enable func-name-matching */
97+
if (type && data) {
98+
const filename = `${this._id}_${Math.round(
99+
Date.now() / 1000
100+
).toString(36)}.${type}`;
101+
try {
102+
fs.writeFileSync(`${imageFolder}${filename}`, data);
103+
} catch (err) {
104+
log.warn(err);
105+
106+
return;
107+
}
105108

106-
return filename;
107-
} else if (deleteImage === true) {
108-
if (this.image) {
109-
const oldFilename = `${imageFolder}${this.image}`;
110-
const extensionToUse = this.image.slice(this.image.lastIndexOf('.'));
111-
const newFilename = `${imageFolder}${Buffer.from((Buffer.from(`${Math.random().toString(36)
112-
.slice(2)}${Date.now()}`).toString('base64'))).toString('hex')}${extensionToUse}`;
113-
fs.rename(oldFilename, newFilename, () => {});
109+
return filename;
110+
} else if (deleteImage === true) {
111+
if (this.image) {
112+
const oldFilename = `${imageFolder}${this.image}`;
113+
const extensionToUse = this.image.slice(
114+
this.image.lastIndexOf('.')
115+
);
116+
const newFilename = `${imageFolder}${Buffer.from(
117+
Buffer.from(
118+
`${Math.random().toString(36)
119+
.slice(2)}${Date.now()}`
120+
).toString('base64')
121+
).toString('hex')}${extensionToUse}`;
122+
fs.rename(oldFilename, newFilename, () => {});
123+
}
114124
}
115125
}
126+
},
127+
sensors: {
128+
type: [sensorSchema],
129+
// required: [true, 'sensors are required if model is invalid or missing.'],
130+
// https://github.com/Automattic/mongoose/issues/5139#issuecomment-429990002
131+
validate: {
132+
validator: (v) => {
133+
return v === null || v.length > 0;
134+
},
135+
message: () => 'sensors are required if model is invalid or missing.'
136+
}
137+
},
138+
lastMeasurementAt: {
139+
type: Date,
140+
required: false
141+
},
142+
access_token: {
143+
type: String,
144+
required: true
145+
},
146+
useAuth: {
147+
type: Boolean,
148+
required: true,
149+
default: false
116150
}
117151
},
118-
sensors: {
119-
type: [sensorSchema],
120-
required: [true, 'sensors are required if model is invalid or missing.'],
121-
},
122-
lastMeasurementAt: {
123-
type: Date,
124-
required: false
125-
},
126-
access_token: {
127-
type: String,
128-
required: true
129-
},
130-
useAuth: {
131-
type: Boolean,
132-
required: true,
133-
default: false,
134-
}
135-
}, { usePushEach: true });
152+
{ usePushEach: true }
153+
);
136154
boxSchema.plugin(timestamp);
137155

138156
const BOX_PROPS_FOR_POPULATION = {

packages/models/src/box/integrations.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ const integrationSchema = new mongoose.Schema({
5757
validator: function validTTNDecodeOptions (ttn) {
5858
/* eslint-enable func-name-matching */
5959
if (['debug', 'lora-serialization', 'cayenne-lpp'].indexOf(ttn.profile) !== -1) {
60-
return (ttn.decodeOptions && ttn.decodeOptions.constructor === Array);
60+
return (ttn.decodeOptions && Array.isArray(ttn.decodeOptions));
6161
}
6262
},
6363
msg: 'this profile requires an array \'decodeOptions\''

packages/models/src/db.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ const connect = function connect (uri) {
3838
return new Promise(function (resolve, reject) {
3939
mongoose
4040
.connect(uri, {
41-
useMongoClient: true,
42-
reconnectTries: Number.MAX_VALUE,
41+
useNewUrlParser: true,
42+
useUnifiedTopology: true,
4343
promiseLibrary: global.Promise
4444
})
4545
.then(function () {

packages/models/test/tests/0-user.js

+19-8
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,18 @@ const shouldNotHappenThenner = function (err) {
1515
expect(false).true;
1616
};
1717

18+
const getDevices = function () {
19+
const boxes = [
20+
senseBox({ name: 'sb1' }),
21+
senseBox({ name: 'sb2' }),
22+
senseBox({ name: 'sb3' })
23+
];
24+
25+
return new Promise((resolve) => {
26+
setTimeout(() => resolve(boxes), 200);
27+
});
28+
};
29+
1830
describe('User model', function () {
1931
before(function () {
2032
return connect(dbConnectionString({ db: 'userTest' }))
@@ -506,15 +518,14 @@ describe('User model', function () {
506518
});
507519

508520
describe('Box management', function () {
509-
const boxes = [senseBox({ name: 'sb1' }), senseBox({ name: 'sb2' }), senseBox({ name: 'sb3' })];
510521
let userBoxes;
511-
before(function () {
512-
return User.findOne({ name: 'Valid Username 2' })
513-
.then(function (user) {
514-
return Promise.all(boxes.map(function (box) {
515-
return user.addBox(box);
516-
}));
517-
});
522+
before(async function () {
523+
const user = await User.findOne({ name: 'Valid Username 2' });
524+
525+
const devices = await getDevices();
526+
for (const device of devices) {
527+
await user.addBox(device);
528+
}
518529
});
519530

520531
it('should allow to get all boxes with all details of a user', function () {

0 commit comments

Comments
 (0)