Case insensitive signup (#5634)
* Always delete data after each, even for mongo. * Add failing simple case test * run all tests * 1. when validating username be case insensitive 2. add _auth_data_anonymous to specialQueryKeys...whatever that is! * More case sensitivity 1. also make email validation case insensitive 2. update comments to reflect what this change does * wordsmithery and grammar * first pass at a preformant case insensitive query. mongo only so far. * change name of parameter from insensitive to caseInsensitive * Postgres support * properly handle auth data null * wip * use 'caseInsensitive' instead of 'insensitive' in all places. * update commenet to reclect current plan * skip the mystery test for now * create case insensitive indecies for mongo to support case insensitive checks for email and username * remove unneeded specialKey * pull collation out to a function. * not sure what i planned to do with this test. removing. * remove typo * remove another unused flag * maintain order * maintain order of params * boil the ocean on param sequence i like having explain last cause it seems like something you would change/remove after getting what you want from the explain? * add test to verify creation and use of caseInsensitive index * add no op func to prostgress * get collation object from mongocollection make flow lint happy by declaring things Object. * fix typo * add changelog * kick travis * properly reference static method * add a test to confirm that anonymous users with unique username that do collide when compared insensitively can still be created. * minot doc nits * add a few tests to make sure our spy is working as expected wordsmith the changelog Co-authored-by: Diamond Lewis <findlewis@gmail.com>
This commit is contained in:
@@ -254,7 +254,12 @@ interface WhereClause {
|
||||
sorts: Array<any>;
|
||||
}
|
||||
|
||||
const buildWhereClause = ({ schema, query, index }): WhereClause => {
|
||||
const buildWhereClause = ({
|
||||
schema,
|
||||
query,
|
||||
index,
|
||||
caseInsensitive,
|
||||
}): WhereClause => {
|
||||
const patterns = [];
|
||||
let values = [];
|
||||
const sorts = [];
|
||||
@@ -276,10 +281,24 @@ const buildWhereClause = ({ schema, query, index }): WhereClause => {
|
||||
}
|
||||
}
|
||||
|
||||
if (fieldName.indexOf('.') >= 0) {
|
||||
const authDataMatch = fieldName.match(/^_auth_data_([a-zA-Z0-9_]+)$/);
|
||||
if (authDataMatch) {
|
||||
// TODO: Handle querying by _auth_data_provider, authData is stored in authData field
|
||||
continue;
|
||||
} else if (
|
||||
caseInsensitive &&
|
||||
(fieldName === 'username' || fieldName === 'email')
|
||||
) {
|
||||
patterns.push(`LOWER($${index}:name) = LOWER($${index + 1})`);
|
||||
values.push(fieldName, fieldValue);
|
||||
index += 2;
|
||||
} else if (fieldName.indexOf('.') >= 0) {
|
||||
let name = transformDotField(fieldName);
|
||||
if (fieldValue === null) {
|
||||
patterns.push(`${name} IS NULL`);
|
||||
patterns.push(`$${index}:raw IS NULL`);
|
||||
values.push(name);
|
||||
index += 1;
|
||||
continue;
|
||||
} else {
|
||||
if (fieldValue.$in) {
|
||||
name = transformDotFieldToComponents(fieldName).join('->');
|
||||
@@ -325,7 +344,12 @@ const buildWhereClause = ({ schema, query, index }): WhereClause => {
|
||||
const clauses = [];
|
||||
const clauseValues = [];
|
||||
fieldValue.forEach(subQuery => {
|
||||
const clause = buildWhereClause({ schema, query: subQuery, index });
|
||||
const clause = buildWhereClause({
|
||||
schema,
|
||||
query: subQuery,
|
||||
index,
|
||||
caseInsensitive,
|
||||
});
|
||||
if (clause.pattern.length > 0) {
|
||||
clauses.push(clause.pattern);
|
||||
clauseValues.push(...clause.values);
|
||||
@@ -464,10 +488,16 @@ const buildWhereClause = ({ schema, query, index }): WhereClause => {
|
||||
}
|
||||
};
|
||||
if (fieldValue.$in) {
|
||||
createConstraint(_.flatMap(fieldValue.$in, elt => elt), false);
|
||||
createConstraint(
|
||||
_.flatMap(fieldValue.$in, elt => elt),
|
||||
false
|
||||
);
|
||||
}
|
||||
if (fieldValue.$nin) {
|
||||
createConstraint(_.flatMap(fieldValue.$nin, elt => elt), true);
|
||||
createConstraint(
|
||||
_.flatMap(fieldValue.$nin, elt => elt),
|
||||
true
|
||||
);
|
||||
}
|
||||
} else if (typeof fieldValue.$in !== 'undefined') {
|
||||
throw new Parse.Error(Parse.Error.INVALID_JSON, 'bad $in value');
|
||||
@@ -1437,7 +1467,12 @@ export class PostgresStorageAdapter implements StorageAdapter {
|
||||
debug('deleteObjectsByQuery', className, query);
|
||||
const values = [className];
|
||||
const index = 2;
|
||||
const where = buildWhereClause({ schema, index, query });
|
||||
const where = buildWhereClause({
|
||||
schema,
|
||||
index,
|
||||
query,
|
||||
caseInsensitive: false,
|
||||
});
|
||||
values.push(...where.values);
|
||||
if (Object.keys(query).length === 0) {
|
||||
where.pattern = 'TRUE';
|
||||
@@ -1744,7 +1779,12 @@ export class PostgresStorageAdapter implements StorageAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
const where = buildWhereClause({ schema, index, query });
|
||||
const where = buildWhereClause({
|
||||
schema,
|
||||
index,
|
||||
query,
|
||||
caseInsensitive: false,
|
||||
});
|
||||
values.push(...where.values);
|
||||
|
||||
const whereClause =
|
||||
@@ -1795,13 +1835,24 @@ export class PostgresStorageAdapter implements StorageAdapter {
|
||||
className: string,
|
||||
schema: SchemaType,
|
||||
query: QueryType,
|
||||
{ skip, limit, sort, keys }: QueryOptions
|
||||
{ skip, limit, sort, keys, caseInsensitive }: QueryOptions
|
||||
) {
|
||||
debug('find', className, query, { skip, limit, sort, keys });
|
||||
debug('find', className, query, {
|
||||
skip,
|
||||
limit,
|
||||
sort,
|
||||
keys,
|
||||
caseInsensitive,
|
||||
});
|
||||
const hasLimit = limit !== undefined;
|
||||
const hasSkip = skip !== undefined;
|
||||
let values = [className];
|
||||
const where = buildWhereClause({ schema, query, index: 2 });
|
||||
const where = buildWhereClause({
|
||||
schema,
|
||||
query,
|
||||
index: 2,
|
||||
caseInsensitive,
|
||||
});
|
||||
values.push(...where.values);
|
||||
|
||||
const wherePattern =
|
||||
@@ -2027,7 +2078,12 @@ export class PostgresStorageAdapter implements StorageAdapter {
|
||||
) {
|
||||
debug('count', className, query, readPreference, estimate);
|
||||
const values = [className];
|
||||
const where = buildWhereClause({ schema, query, index: 2 });
|
||||
const where = buildWhereClause({
|
||||
schema,
|
||||
query,
|
||||
index: 2,
|
||||
caseInsensitive: false,
|
||||
});
|
||||
values.push(...where.values);
|
||||
|
||||
const wherePattern =
|
||||
@@ -2080,7 +2136,12 @@ export class PostgresStorageAdapter implements StorageAdapter {
|
||||
schema.fields[fieldName] &&
|
||||
schema.fields[fieldName].type === 'Pointer';
|
||||
const values = [field, column, className];
|
||||
const where = buildWhereClause({ schema, query, index: 4 });
|
||||
const where = buildWhereClause({
|
||||
schema,
|
||||
query,
|
||||
index: 4,
|
||||
caseInsensitive: false,
|
||||
});
|
||||
values.push(...where.values);
|
||||
|
||||
const wherePattern =
|
||||
@@ -2364,7 +2425,11 @@ export class PostgresStorageAdapter implements StorageAdapter {
|
||||
});
|
||||
}
|
||||
|
||||
async createIndexes(className: string, indexes: any, conn: ?any): Promise<void> {
|
||||
async createIndexes(
|
||||
className: string,
|
||||
indexes: any,
|
||||
conn: ?any
|
||||
): Promise<void> {
|
||||
return (conn || this._client).tx(t =>
|
||||
t.batch(
|
||||
indexes.map(i => {
|
||||
@@ -2384,10 +2449,13 @@ export class PostgresStorageAdapter implements StorageAdapter {
|
||||
type: any,
|
||||
conn: ?any
|
||||
): Promise<void> {
|
||||
await (conn || this._client).none(
|
||||
'CREATE INDEX $1:name ON $2:name ($3:name)',
|
||||
[fieldName, className, type]
|
||||
);
|
||||
await (
|
||||
conn || this._client
|
||||
).none('CREATE INDEX $1:name ON $2:name ($3:name)', [
|
||||
fieldName,
|
||||
className,
|
||||
type,
|
||||
]);
|
||||
}
|
||||
|
||||
async dropIndexes(className: string, indexes: any, conn: any): Promise<void> {
|
||||
@@ -2444,6 +2512,11 @@ export class PostgresStorageAdapter implements StorageAdapter {
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO: implement?
|
||||
ensureIndex(): Promise<void> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
function convertPolygonToSQL(polygon) {
|
||||
|
||||
Reference in New Issue
Block a user