Compare commits

...

4 Commits

Author SHA1 Message Date
Alexander Chan 3610a6807d changes 2019-11-21 15:57:23 -08:00
Alexander Chan 4cda6054a3 tmp 2019-11-21 12:18:12 -08:00
Alexander Chan 35711037d7 changes 2019-11-19 15:27:25 -08:00
Alexander Chan 8fde2a7980 conditional updates 2019-11-19 15:13:06 -08:00
3 changed files with 196 additions and 0 deletions

View File

@ -356,6 +356,7 @@ class MultipleBackendGateway {
getDiskUsage(config, reqUids, callback) { getDiskUsage(config, reqUids, callback) {
new DataFileBackend(config).getDiskUsage(config, reqUids, callback); new DataFileBackend(config).getDiskUsage(config, reqUids, callback);
} }
} }
module.exports = MultipleBackendGateway; module.exports = MultipleBackendGateway;

View File

@ -356,6 +356,12 @@ class MetadataWrapper {
notifyBucketChange(cb) { notifyBucketChange(cb) {
bucketNotificationHook = cb; bucketNotificationHook = cb;
} }
close() {
if (this.client.close === 'function') {
this.client.close();
}
}
} }
module.exports = MetadataWrapper; module.exports = MetadataWrapper;

View File

@ -14,6 +14,7 @@ const async = require('async');
const { EventEmitter } = require('events'); const { EventEmitter } = require('events');
const constants = require('../../../constants'); const constants = require('../../../constants');
const { reshapeExceptionError } = require('../../../errorUtils');
const errors = require('../../../errors'); const errors = require('../../../errors');
const BucketInfo = require('../../../models/BucketInfo'); const BucketInfo = require('../../../models/BucketInfo');
@ -62,6 +63,45 @@ function inc(str) {
const VID_SEPPLUS = inc(VID_SEP); const VID_SEPPLUS = inc(VID_SEP);
const MONGODB_QUERY_OPERATORS = [
'$eq',
'$gt',
'$gte',
'$in',
'$lt',
'$lte',
'$ne',
'$nin',
'$and',
'$not',
'$nor',
'$or',
'$exists',
'$type',
'$expr',
'$jsonSchema',
'$mod',
'$regex',
'$text',
'$where',
'$geoIntersects',
'$geoWithin',
'$near',
'$nearSphere',
'$all',
'$elemMatch',
'$size',
'$bitsAllClear',
'$bitsAllSet',
'$bitsAnyClear',
'$bitsAnySet',
'$comment',
'$',
'$elemMatch',
'$meta',
'$slice',
];
function generatePHDVersion(versionId) { function generatePHDVersion(versionId) {
return { return {
isPHD: true, isPHD: true,
@ -622,6 +662,10 @@ class MongoClientInterface {
return this.putObjectVerCase4(c, bucketName, objName, objVal, return this.putObjectVerCase4(c, bucketName, objName, objVal,
params, log, cb); params, log, cb);
} }
if (params && params.query) {
return this.putObjectNoVerConditional(
c, bucketName, objName, objVal, params, log, cb);
}
return this.putObjectNoVer(c, bucketName, objName, objVal, return this.putObjectNoVer(c, bucketName, objName, objVal,
params, log, cb); params, log, cb);
} }
@ -915,6 +959,10 @@ class MongoClientInterface {
return this.deleteObjectVer(c, bucketName, objName, return this.deleteObjectVer(c, bucketName, objName,
params, log, cb); params, log, cb);
} }
if (params && params.query) {
return this.deleteObjectNoVerConditional(
c, bucketName, objName, params, log, cb);
}
return this.deleteObjectNoVer(c, bucketName, objName, return this.deleteObjectNoVer(c, bucketName, objName,
params, log, cb); params, log, cb);
} }
@ -1634,6 +1682,147 @@ class MongoClientInterface {
return cb(null, doc.map(i => i.value)); return cb(null, doc.map(i => i.value));
}); });
} }
/*
* converts regular js object into mongodb usable filters
* Example: with starting prefix ""
* {
* hello: {
* world: {
* $eq: 42
* }
* }
* }
* is will be parsed as
* {
* "hello.world": { $eq: 42 }
* }
*
*/
_genMongoQuery(depth, prefix, object, query) {
/* eslint-disable no-param-reassign */
if (depth > 10) {
throw errors.InternalError;
}
if (typeof query !== 'object' ||
query === null ||
query === undefined) {
object[prefix] = query;
return;
}
const fields = Object.keys(query);
if (fields.some(f => MONGODB_QUERY_OPERATORS.includes(f))) {
object[prefix] = query;
} else {
fields.forEach(f => this._genMongoQuery(depth + 1,
`${prefix}.${f}`,
object, query[f])
);
}
return;
/* eslint-enable no-param-reassign */
}
_getFilter(objName, query) {
const filter = { _id: objName };
this._genMongoQuery(0, 'value', filter, query);
return filter;
}
/*
* delete an object that matches a given query object
*/
deleteObjectNoVerConditional(c, bucketName, objName, params, log, cb) {
const method = 'deleteObjectNoVerConditional';
let filter;
try {
filter = this._getFilter(objName, params.query);
} catch (err) {
log.error('error creating mongodb filter', {
error: reshapeExceptionError(err),
});
return cb(errors.InternalError);
}
return c.findOneAndDelete(filter, (err, res) => {
if (err) {
log.error('error occurred when attempting to delete object', {
method,
error: err.message,
});
return cb(errors.InternalError);
}
if (res.ok !== 1) {
log.error('failed to delete object', {
method,
error: err.message,
});
return cb(errors.InternalError);
}
/*
* unable to find an object that matches the query
*/
if (!res.value) {
log.debug('unable to find target object to delete', {
method,
filter,
});
return cb(errors.NoSuchKey);
}
return cb();
});
}
/*
* update an object that matches a given query. If one cannot be found,
* a new object will be inserted
*/
putObjectNoVerConditional(c, bucketName, objName, objVal, params, log, cb) {
const method = 'putObjectNoVerConditional';
let filter;
try {
filter = this._getFilter(objName, params.query);
} catch (err) {
log.error('error creating mongodb filter', {
error: reshapeExceptionError(err),
});
return cb(errors.InternalError);
}
return c.findOneAndUpdate(filter, {
$set: {
_id: objName,
value: objVal,
},
}, {
upsert: true,
}, (err, res) => {
if (err) {
log.error('error occurred when attempting update object', {
method,
error: err,
});
return cb(errors.InternalError);
}
if (res.ok !== 1) {
log.error('failed to update object', {
method,
error: err.message,
});
return cb(errors.InternalError);
}
if (!res.value) {
log.debug('object not found...inserting object', {
method,
filter,
});
return cb();
}
log.debug('Object found...updating object', {
method,
filter,
});
return cb();
});
}
} }
module.exports = MongoClientInterface; module.exports = MongoClientInterface;