Merge pull request #1888 from drew-gross/finish-moving-query-logic

Finish moving query logic
This commit is contained in:
Peter J. Shin
2016-05-24 16:38:14 -07:00
7 changed files with 85 additions and 96 deletions

View File

@@ -198,11 +198,18 @@ export class MongoStorageAdapter {
}
// Executes a find. Accepts: className, query in Parse format, and { skip, limit, sort }.
// Accepts the schemaController for legacy reasons.
find(className, query, { skip, limit, sort }, schemaController) {
find(className, query, schema, { skip, limit, sort }) {
let mongoWhere = this.transform.transformWhere(className, query, schema);
let mongoSort = _.mapKeys(sort, (value, fieldName) => transform.transformKey(className, fieldName, schema));
return this.adaptiveCollection(className)
.then(collection => collection.find(query, { skip, limit, sort }))
.then(objects => objects.map(object => transform.mongoObjectToParseObject(schemaController, className, object)));
.then(collection => collection.find(mongoWhere, { skip, limit, sort: mongoSort }))
.then(objects => objects.map(object => transform.mongoObjectToParseObject(className, object, schema)));
}
// Executs a count.
count(className, query, schema) {
return this.adaptiveCollection(className)
.then(collection => collection.count(transform.transformWhere(className, query, schema)));
}
get transform() {

View File

@@ -755,7 +755,7 @@ const nestedMongoObjectToNestedParseObject = mongoObject => {
// Converts from a mongo-format object to a REST-format object.
// Does not strip out anything based on a lack of authentication.
const mongoObjectToParseObject = (schema, className, mongoObject) => {
const mongoObjectToParseObject = (className, mongoObject, schema) => {
switch(typeof mongoObject) {
case 'string':
case 'number':
@@ -830,17 +830,11 @@ const mongoObjectToParseObject = (schema, className, mongoObject) => {
if (key.indexOf('_p_') == 0) {
var newKey = key.substring(3);
var expected;
if (schema && schema.getExpectedType) {
expected = schema.getExpectedType(className, newKey);
}
if (!expected) {
log.info('transform.js',
'Found a pointer column not in the schema, dropping it.',
className, newKey);
if (!schema.fields[newKey]) {
log.info('transform.js', 'Found a pointer column not in the schema, dropping it.', className, newKey);
break;
}
if (expected && expected.type !== 'Pointer') {
if (schema.fields[newKey].type !== 'Pointer') {
log.info('transform.js', 'Found a pointer in a non-pointer column, dropping it.', className, key);
break;
}
@@ -848,8 +842,7 @@ const mongoObjectToParseObject = (schema, className, mongoObject) => {
break;
}
var objData = mongoObject[key].split('$');
var newClass = (expected ? expected.targetClass : objData[0]);
if (objData[0] !== newClass) {
if (objData[0] !== schema.fields[newKey].targetClass) {
throw 'pointer to incorrect className';
}
restObject[newKey] = {
@@ -861,13 +854,12 @@ const mongoObjectToParseObject = (schema, className, mongoObject) => {
} else if (key[0] == '_' && key != '__type') {
throw ('bad key in untransform: ' + key);
} else {
var expectedType = schema.getExpectedType(className, key);
var value = mongoObject[key];
if (expectedType && expectedType.type === 'File' && FileCoder.isValidDatabaseObject(value)) {
if (schema.fields[key] && schema.fields[key].type === 'File' && FileCoder.isValidDatabaseObject(value)) {
restObject[key] = FileCoder.databaseToJSON(value);
break;
}
if (expectedType && expectedType.type === 'GeoPoint' && GeoPointCoder.isValidDatabaseObject(value)) {
if (schema.fields[key] && schema.fields[key].type === 'GeoPoint' && GeoPointCoder.isValidDatabaseObject(value)) {
restObject[key] = GeoPointCoder.databaseToJSON(value);
break;
}
@@ -876,7 +868,16 @@ const mongoObjectToParseObject = (schema, className, mongoObject) => {
}
}
return { ...restObject, ...schema.getRelationFields(className) };
const relationFieldNames = Object.keys(schema.fields).filter(fieldName => schema.fields[fieldName].type === 'Relation');
let relationFields = {};
relationFieldNames.forEach(relationFieldName => {
relationFields[relationFieldName] = {
__type: 'Relation',
className: schema.fields[relationFieldName].targetClass,
}
});
return { ...restObject, ...relationFields };
default:
throw 'unknown js type';
}

View File

@@ -628,16 +628,9 @@ DatabaseController.prototype.find = function(className, query, {
skip,
limit,
acl,
sort,
sort = {},
count,
} = {}) {
let mongoOptions = {};
if (skip) {
mongoOptions.skip = skip;
}
if (limit) {
mongoOptions.limit = limit;
}
let isMaster = acl === undefined;
let aclGroup = acl || [];
let op = typeof query.objectId == 'string' && Object.keys(query).length === 1 ? 'get' : 'find';
@@ -653,34 +646,29 @@ DatabaseController.prototype.find = function(className, query, {
throw error;
})
.then(schema => {
if (sort) {
mongoOptions.sort = {};
for (let fieldName in sort) {
// Parse.com treats queries on _created_at and _updated_at as if they were queries on createdAt and updatedAt,
// so duplicate that behaviour here.
if (fieldName === '_created_at') {
fieldName = 'createdAt';
sort['createdAt'] = sort['_created_at'];
} else if (fieldName === '_updated_at') {
fieldName = 'updatedAt';
sort['updatedAt'] = sort['_updated_at'];
}
if (!SchemaController.fieldNameIsValid(fieldName)) {
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Invalid field name: ${fieldName}.`);
}
if (fieldName.match(/^authData\.([a-zA-Z0-9_]+)\.id$/)) {
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Cannot sort by ${fieldName}`);
}
const mongoKey = this.transform.transformKey(className, fieldName, schema);
mongoOptions.sort[mongoKey] = sort[fieldName];
}
// Parse.com treats queries on _created_at and _updated_at as if they were queries on createdAt and updatedAt,
// so duplicate that behaviour here. If both are specified, the corrent behaviour to match Parse.com is to
// use the one that appears first in the sort list.
if (sort._created_at) {
sort.createdAt = sort._created_at;
delete sort._created_at;
}
if (sort._updated_at) {
sort.updatedAt = sort._updated_at;
delete sort._updated_at;
}
Object.keys(sort).forEach(fieldName => {
if (fieldName.match(/^authData\.([a-zA-Z0-9_]+)\.id$/)) {
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Cannot sort by ${fieldName}`);
}
if (!SchemaController.fieldNameIsValid(fieldName)) {
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Invalid field name: ${fieldName}.`);
}
});
return (isMaster ? Promise.resolve() : schemaController.validatePermission(className, aclGroup, op))
.then(() => this.reduceRelationKeys(className, query))
.then(() => this.reduceInRelation(className, query, schemaController))
.then(() => this.adapter.adaptiveCollection(className))
.then(collection => {
.then(() => {
if (!isMaster) {
query = this.addPointerPermissions(schemaController, className, op, query, aclGroup);
}
@@ -696,12 +684,10 @@ DatabaseController.prototype.find = function(className, query, {
query = addReadACL(query, aclGroup);
}
validateQuery(query);
let mongoWhere = this.transform.transformWhere(className, query, schema);
if (count) {
delete mongoOptions.limit;
return collection.count(mongoWhere, mongoOptions);
return this.adapter.count(className, query, schema);
} else {
return this.adapter.find(className, mongoWhere, mongoOptions, schemaController)
return this.adapter.find(className, query, schema, { skip, limit, sort })
.then(objects => objects.map(object => filterSensitiveData(isMaster, aclGroup, className, object)));
}
});

View File

@@ -686,23 +686,6 @@ class SchemaController {
hasClass(className) {
return this.reloadData().then(() => !!(this.data[className]));
}
getRelationFields(className) {
if (this.data && this.data[className]) {
let classData = this.data[className];
return Object.keys(classData).filter((field) => {
return classData[field].type === 'Relation';
}).reduce((memo, field) => {
let type = classData[field];
memo[field] = {
__type: 'Relation',
className: type.targetClass
};
return memo;
}, {});
}
return {};
}
}
// Returns a promise for a new Schema.