Skip to content

Commit e0a9f19

Browse files
committed
Split logic for transforming queries into it's own function
1 parent 21e73ac commit e0a9f19

File tree

1 file changed

+126
-45
lines changed

1 file changed

+126
-45
lines changed

src/Adapters/Storage/Mongo/MongoTransform.js

Lines changed: 126 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,16 @@ var Parse = require('parse/node').Parse;
1111
//
1212
// There are several options that can help transform:
1313
//
14-
// query: true indicates that query constraints like $lt are allowed in
15-
// the value.
16-
//
1714
// update: true indicates that __op operators like Add and Delete
1815
// in the value are converted to a mongo update form. Otherwise they are
1916
// converted to static data.
2017
//
2118
// validate: true indicates that key names are to be validated.
2219
//
2320
// Returns an object with {key: key, value: value}.
24-
export function transformKeyValue(schema, className, restKey, restValue, {
21+
function transformKeyValue(schema, className, restKey, restValue, {
2522
inArray,
2623
inObject,
27-
query,
2824
update,
2925
validate,
3026
} = {}) {
@@ -66,26 +62,128 @@ export function transformKeyValue(schema, className, restKey, restValue, {
6662
return {key: key, value: restValue};
6763
break;
6864
case '$or':
69-
if (!query) {
70-
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME,
71-
'you can only use $or in queries');
65+
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'you can only use $or in queries');
66+
case '$and':
67+
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'you can only use $and in queries');
68+
default:
69+
// Other auth data
70+
var authDataMatch = key.match(/^authData\.([a-zA-Z0-9_]+)\.id$/);
71+
if (authDataMatch) {
72+
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'can only query on ' + key);
73+
}
74+
if (validate && !key.match(/^[a-zA-Z][a-zA-Z0-9_\.]*$/)) {
75+
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'invalid key name: ' + key);
7276
}
77+
}
78+
79+
// Handle special schema key changes
80+
// TODO: it seems like this is likely to have edge cases where
81+
// pointer types are missed
82+
var expected = undefined;
83+
if (schema && schema.getExpectedType) {
84+
expected = schema.getExpectedType(className, key);
85+
}
86+
if ((expected && expected.type == 'Pointer') ||
87+
(!expected && restValue && restValue.__type == 'Pointer')) {
88+
key = '_p_' + key;
89+
}
90+
var expectedTypeIsArray = (expected && expected.type === 'Array');
91+
92+
// Handle atomic values
93+
var value = transformAtom(restValue, false, { inArray, inObject });
94+
if (value !== CannotTransform) {
95+
if (timeField && (typeof value === 'string')) {
96+
value = new Date(value);
97+
}
98+
return {key: key, value: value};
99+
}
100+
101+
// ACLs are handled before this method is called
102+
// If an ACL key still exists here, something is wrong.
103+
if (key === 'ACL') {
104+
throw 'There was a problem transforming an ACL.';
105+
}
106+
107+
// Handle arrays
108+
if (restValue instanceof Array) {
109+
value = restValue.map((restObj) => {
110+
var out = transformKeyValue(schema, className, restKey, restObj, { inArray: true });
111+
return out.value;
112+
});
113+
return {key: key, value: value};
114+
}
115+
116+
// Handle update operators
117+
value = transformUpdateOperator(restValue, !update);
118+
if (value !== CannotTransform) {
119+
return {key: key, value: value};
120+
}
121+
122+
// Handle normal objects by recursing
123+
value = {};
124+
for (var subRestKey in restValue) {
125+
var subRestValue = restValue[subRestKey];
126+
var out = transformKeyValue(schema, className, subRestKey, subRestValue, { inObject: true });
127+
// For recursed objects, keep the keys in rest format
128+
value[subRestKey] = out.value;
129+
}
130+
return {key: key, value: value};
131+
}
132+
133+
function transformQueryKeyValue(schema, className, restKey, restValue, {
134+
inArray,
135+
inObject,
136+
update,
137+
validate,
138+
} = {}) {
139+
// Check if the schema is known since it's a built-in field.
140+
var key = restKey;
141+
var timeField = false;
142+
switch(key) {
143+
case 'objectId':
144+
case '_id':
145+
key = '_id';
146+
break;
147+
case 'createdAt':
148+
case '_created_at':
149+
key = '_created_at';
150+
timeField = true;
151+
break;
152+
case 'updatedAt':
153+
case '_updated_at':
154+
key = '_updated_at';
155+
timeField = true;
156+
break;
157+
case '_email_verify_token':
158+
key = "_email_verify_token";
159+
break;
160+
case '_perishable_token':
161+
key = "_perishable_token";
162+
break;
163+
case 'sessionToken':
164+
case '_session_token':
165+
key = '_session_token';
166+
break;
167+
case 'expiresAt':
168+
case '_expiresAt':
169+
key = 'expiresAt';
170+
timeField = true;
171+
break;
172+
case '_rperm':
173+
case '_wperm':
174+
return {key: key, value: restValue};
175+
break;
176+
case '$or':
73177
if (!(restValue instanceof Array)) {
74-
throw new Parse.Error(Parse.Error.INVALID_QUERY,
75-
'bad $or format - use an array value');
178+
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'bad $or format - use an array value');
76179
}
77180
var mongoSubqueries = restValue.map((s) => {
78181
return transformWhere(schema, className, s);
79182
});
80183
return {key: '$or', value: mongoSubqueries};
81184
case '$and':
82-
if (!query) {
83-
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME,
84-
'you can only use $and in queries');
85-
}
86185
if (!(restValue instanceof Array)) {
87-
throw new Parse.Error(Parse.Error.INVALID_QUERY,
88-
'bad $and format - use an array value');
186+
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'bad $and format - use an array value');
89187
}
90188
var mongoSubqueries = restValue.map((s) => {
91189
return transformWhere(schema, className, s);
@@ -94,19 +192,13 @@ export function transformKeyValue(schema, className, restKey, restValue, {
94192
default:
95193
// Other auth data
96194
var authDataMatch = key.match(/^authData\.([a-zA-Z0-9_]+)\.id$/);
97-
if (authDataMatch) {
98-
if (query) {
99-
var provider = authDataMatch[1];
100-
// Special-case auth data.
101-
return {key: '_auth_data_'+provider+'.id', value: restValue};
102-
}
103-
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME,
104-
'can only query on ' + key);
105-
break;
106-
};
195+
if (authDataMatch ) {
196+
var provider = authDataMatch[1];
197+
// Special-case auth data.
198+
return {key: '_auth_data_'+provider+'.id', value: restValue};
199+
}
107200
if (validate && !key.match(/^[a-zA-Z][a-zA-Z0-9_\.]*$/)) {
108-
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME,
109-
'invalid key name: ' + key);
201+
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, 'invalid key name: ' + key);
110202
}
111203
}
112204

@@ -124,14 +216,12 @@ export function transformKeyValue(schema, className, restKey, restValue, {
124216
var expectedTypeIsArray = (expected && expected.type === 'Array');
125217

126218
// Handle query constraints
127-
if (query) {
128-
value = transformConstraint(restValue, expectedTypeIsArray);
129-
if (value !== CannotTransform) {
130-
return {key: key, value: value};
131-
}
219+
value = transformConstraint(restValue, expectedTypeIsArray);
220+
if (value !== CannotTransform) {
221+
return {key: key, value: value};
132222
}
133223

134-
if (expectedTypeIsArray && query && !(restValue instanceof Array)) {
224+
if (expectedTypeIsArray && !(restValue instanceof Array)) {
135225
return {
136226
key: key, value: { '$all' : [restValue] }
137227
};
@@ -154,15 +244,7 @@ export function transformKeyValue(schema, className, restKey, restValue, {
154244

155245
// Handle arrays
156246
if (restValue instanceof Array) {
157-
if (query) {
158-
throw new Parse.Error(Parse.Error.INVALID_JSON,
159-
'cannot use array as query param');
160-
}
161-
value = restValue.map((restObj) => {
162-
var out = transformKeyValue(schema, className, restKey, restObj, { inArray: true });
163-
return out.value;
164-
});
165-
return {key: key, value: value};
247+
throw new Parse.Error(Parse.Error.INVALID_JSON,'cannot use array as query param');
166248
}
167249

168250
// Handle update operators
@@ -182,7 +264,6 @@ export function transformKeyValue(schema, className, restKey, restValue, {
182264
return {key: key, value: value};
183265
}
184266

185-
186267
// Main exposed method to help run queries.
187268
// restWhere is the "where" clause in REST API form.
188269
// Returns the mongo form of the query.
@@ -193,7 +274,7 @@ function transformWhere(schema, className, restWhere, { validate = true } = {})
193274
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Cannot query on ACL.');
194275
}
195276
for (let restKey in restWhere) {
196-
let out = transformKeyValue(schema, className, restKey, restWhere[restKey], { query: true, validate });
277+
let out = transformQueryKeyValue(schema, className, restKey, restWhere[restKey], { validate });
197278
mongoWhere[out.key] = out.value;
198279
}
199280
return mongoWhere;

0 commit comments

Comments
 (0)