Do not throw error if user provide a pointer like index onMongo (#6923)
* Do not throw error if user provide a pointer like index on mongo * Add test
This commit is contained in:
@@ -2540,7 +2540,7 @@ describe('schemas', () => {
|
|||||||
|
|
||||||
it('unset field in beforeSave should not stop object creation', done => {
|
it('unset field in beforeSave should not stop object creation', done => {
|
||||||
const hook = {
|
const hook = {
|
||||||
method: function(req) {
|
method: function (req) {
|
||||||
if (req.object.get('undesiredField')) {
|
if (req.object.get('undesiredField')) {
|
||||||
req.object.unset('undesiredField');
|
req.object.unset('undesiredField');
|
||||||
}
|
}
|
||||||
@@ -3110,6 +3110,77 @@ describe('schemas', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it_only_db('mongo')(
|
||||||
|
'lets you add index with with pointer like structure',
|
||||||
|
done => {
|
||||||
|
request({
|
||||||
|
url: 'http://localhost:8378/1/schemas/NewClass',
|
||||||
|
method: 'POST',
|
||||||
|
headers: masterKeyHeaders,
|
||||||
|
json: true,
|
||||||
|
body: {},
|
||||||
|
}).then(() => {
|
||||||
|
request({
|
||||||
|
url: 'http://localhost:8378/1/schemas/NewClass',
|
||||||
|
method: 'PUT',
|
||||||
|
headers: masterKeyHeaders,
|
||||||
|
json: true,
|
||||||
|
body: {
|
||||||
|
fields: {
|
||||||
|
aPointer: { type: 'Pointer', targetClass: 'NewClass' },
|
||||||
|
},
|
||||||
|
indexes: {
|
||||||
|
pointer: { _p_aPointer: 1 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}).then(response => {
|
||||||
|
expect(
|
||||||
|
dd(response.data, {
|
||||||
|
className: 'NewClass',
|
||||||
|
fields: {
|
||||||
|
ACL: { type: 'ACL' },
|
||||||
|
createdAt: { type: 'Date' },
|
||||||
|
updatedAt: { type: 'Date' },
|
||||||
|
objectId: { type: 'String' },
|
||||||
|
aPointer: { type: 'Pointer', targetClass: 'NewClass' },
|
||||||
|
},
|
||||||
|
classLevelPermissions: defaultClassLevelPermissions,
|
||||||
|
indexes: {
|
||||||
|
_id_: { _id: 1 },
|
||||||
|
pointer: { _p_aPointer: 1 },
|
||||||
|
},
|
||||||
|
})
|
||||||
|
).toEqual(undefined);
|
||||||
|
request({
|
||||||
|
url: 'http://localhost:8378/1/schemas/NewClass',
|
||||||
|
headers: masterKeyHeaders,
|
||||||
|
json: true,
|
||||||
|
}).then(response => {
|
||||||
|
expect(response.data).toEqual({
|
||||||
|
className: 'NewClass',
|
||||||
|
fields: {
|
||||||
|
ACL: { type: 'ACL' },
|
||||||
|
createdAt: { type: 'Date' },
|
||||||
|
updatedAt: { type: 'Date' },
|
||||||
|
objectId: { type: 'String' },
|
||||||
|
aPointer: { type: 'Pointer', targetClass: 'NewClass' },
|
||||||
|
},
|
||||||
|
classLevelPermissions: defaultClassLevelPermissions,
|
||||||
|
indexes: {
|
||||||
|
_id_: { _id: 1 },
|
||||||
|
pointer: { _p_aPointer: 1 },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
config.database.adapter.getIndexes('NewClass').then(indexes => {
|
||||||
|
expect(indexes.length).toEqual(2);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
it('lets you add multiple indexes', done => {
|
it('lets you add multiple indexes', done => {
|
||||||
request({
|
request({
|
||||||
url: 'http://localhost:8378/1/schemas/NewClass',
|
url: 'http://localhost:8378/1/schemas/NewClass',
|
||||||
|
|||||||
@@ -34,12 +34,12 @@ const ReadPreference = mongodb.ReadPreference;
|
|||||||
|
|
||||||
const MongoSchemaCollectionName = '_SCHEMA';
|
const MongoSchemaCollectionName = '_SCHEMA';
|
||||||
|
|
||||||
const storageAdapterAllCollections = (mongoAdapter) => {
|
const storageAdapterAllCollections = mongoAdapter => {
|
||||||
return mongoAdapter
|
return mongoAdapter
|
||||||
.connect()
|
.connect()
|
||||||
.then(() => mongoAdapter.database.collections())
|
.then(() => mongoAdapter.database.collections())
|
||||||
.then((collections) => {
|
.then(collections => {
|
||||||
return collections.filter((collection) => {
|
return collections.filter(collection => {
|
||||||
if (collection.namespace.match(/\.system\./)) {
|
if (collection.namespace.match(/\.system\./)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -164,7 +164,7 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
const encodedUri = formatUrl(parseUrl(this._uri));
|
const encodedUri = formatUrl(parseUrl(this._uri));
|
||||||
|
|
||||||
this.connectionPromise = MongoClient.connect(encodedUri, this._mongoOptions)
|
this.connectionPromise = MongoClient.connect(encodedUri, this._mongoOptions)
|
||||||
.then((client) => {
|
.then(client => {
|
||||||
// Starting mongoDB 3.0, the MongoClient.connect don't return a DB anymore but a client
|
// Starting mongoDB 3.0, the MongoClient.connect don't return a DB anymore but a client
|
||||||
// Fortunately, we can get back the options and use them to select the proper DB.
|
// Fortunately, we can get back the options and use them to select the proper DB.
|
||||||
// https://github.com/mongodb/node-mongodb-native/blob/2c35d76f08574225b8db02d7bef687123e6bb018/lib/mongo_client.js#L885
|
// https://github.com/mongodb/node-mongodb-native/blob/2c35d76f08574225b8db02d7bef687123e6bb018/lib/mongo_client.js#L885
|
||||||
@@ -183,7 +183,7 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
this.client = client;
|
this.client = client;
|
||||||
this.database = database;
|
this.database = database;
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch(err => {
|
||||||
delete this.connectionPromise;
|
delete this.connectionPromise;
|
||||||
return Promise.reject(err);
|
return Promise.reject(err);
|
||||||
});
|
});
|
||||||
@@ -212,14 +212,14 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
_adaptiveCollection(name: string) {
|
_adaptiveCollection(name: string) {
|
||||||
return this.connect()
|
return this.connect()
|
||||||
.then(() => this.database.collection(this._collectionPrefix + name))
|
.then(() => this.database.collection(this._collectionPrefix + name))
|
||||||
.then((rawCollection) => new MongoCollection(rawCollection))
|
.then(rawCollection => new MongoCollection(rawCollection))
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
_schemaCollection(): Promise<MongoSchemaCollection> {
|
_schemaCollection(): Promise<MongoSchemaCollection> {
|
||||||
return this.connect()
|
return this.connect()
|
||||||
.then(() => this._adaptiveCollection(MongoSchemaCollectionName))
|
.then(() => this._adaptiveCollection(MongoSchemaCollectionName))
|
||||||
.then((collection) => new MongoSchemaCollection(collection));
|
.then(collection => new MongoSchemaCollection(collection));
|
||||||
}
|
}
|
||||||
|
|
||||||
classExists(name: string) {
|
classExists(name: string) {
|
||||||
@@ -229,20 +229,20 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
.listCollections({ name: this._collectionPrefix + name })
|
.listCollections({ name: this._collectionPrefix + name })
|
||||||
.toArray();
|
.toArray();
|
||||||
})
|
})
|
||||||
.then((collections) => {
|
.then(collections => {
|
||||||
return collections.length > 0;
|
return collections.length > 0;
|
||||||
})
|
})
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
setClassLevelPermissions(className: string, CLPs: any): Promise<void> {
|
setClassLevelPermissions(className: string, CLPs: any): Promise<void> {
|
||||||
return this._schemaCollection()
|
return this._schemaCollection()
|
||||||
.then((schemaCollection) =>
|
.then(schemaCollection =>
|
||||||
schemaCollection.updateSchema(className, {
|
schemaCollection.updateSchema(className, {
|
||||||
$set: { '_metadata.class_permissions': CLPs },
|
$set: { '_metadata.class_permissions': CLPs },
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
setIndexesWithSchemaFormat(
|
setIndexesWithSchemaFormat(
|
||||||
@@ -259,7 +259,7 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
}
|
}
|
||||||
const deletePromises = [];
|
const deletePromises = [];
|
||||||
const insertedIndexes = [];
|
const insertedIndexes = [];
|
||||||
Object.keys(submittedIndexes).forEach((name) => {
|
Object.keys(submittedIndexes).forEach(name => {
|
||||||
const field = submittedIndexes[name];
|
const field = submittedIndexes[name];
|
||||||
if (existingIndexes[name] && field.__op !== 'Delete') {
|
if (existingIndexes[name] && field.__op !== 'Delete') {
|
||||||
throw new Parse.Error(
|
throw new Parse.Error(
|
||||||
@@ -278,8 +278,13 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
deletePromises.push(promise);
|
deletePromises.push(promise);
|
||||||
delete existingIndexes[name];
|
delete existingIndexes[name];
|
||||||
} else {
|
} else {
|
||||||
Object.keys(field).forEach((key) => {
|
Object.keys(field).forEach(key => {
|
||||||
if (!Object.prototype.hasOwnProperty.call(fields, key)) {
|
if (
|
||||||
|
!Object.prototype.hasOwnProperty.call(
|
||||||
|
fields,
|
||||||
|
key.indexOf('_p_') === 0 ? key.replace('_p_', '') : key
|
||||||
|
)
|
||||||
|
) {
|
||||||
throw new Parse.Error(
|
throw new Parse.Error(
|
||||||
Parse.Error.INVALID_QUERY,
|
Parse.Error.INVALID_QUERY,
|
||||||
`Field ${key} does not exist, cannot add index.`
|
`Field ${key} does not exist, cannot add index.`
|
||||||
@@ -300,17 +305,17 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
return Promise.all(deletePromises)
|
return Promise.all(deletePromises)
|
||||||
.then(() => insertPromise)
|
.then(() => insertPromise)
|
||||||
.then(() => this._schemaCollection())
|
.then(() => this._schemaCollection())
|
||||||
.then((schemaCollection) =>
|
.then(schemaCollection =>
|
||||||
schemaCollection.updateSchema(className, {
|
schemaCollection.updateSchema(className, {
|
||||||
$set: { '_metadata.indexes': existingIndexes },
|
$set: { '_metadata.indexes': existingIndexes },
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
setIndexesFromMongo(className: string) {
|
setIndexesFromMongo(className: string) {
|
||||||
return this.getIndexes(className)
|
return this.getIndexes(className)
|
||||||
.then((indexes) => {
|
.then(indexes => {
|
||||||
indexes = indexes.reduce((obj, index) => {
|
indexes = indexes.reduce((obj, index) => {
|
||||||
if (index.key._fts) {
|
if (index.key._fts) {
|
||||||
delete index.key._fts;
|
delete index.key._fts;
|
||||||
@@ -322,13 +327,13 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
obj[index.name] = index.key;
|
obj[index.name] = index.key;
|
||||||
return obj;
|
return obj;
|
||||||
}, {});
|
}, {});
|
||||||
return this._schemaCollection().then((schemaCollection) =>
|
return this._schemaCollection().then(schemaCollection =>
|
||||||
schemaCollection.updateSchema(className, {
|
schemaCollection.updateSchema(className, {
|
||||||
$set: { '_metadata.indexes': indexes },
|
$set: { '_metadata.indexes': indexes },
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.catch((err) => this.handleError(err))
|
.catch(err => this.handleError(err))
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
// Ignore if collection not found
|
// Ignore if collection not found
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
@@ -351,8 +356,8 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
schema.fields
|
schema.fields
|
||||||
)
|
)
|
||||||
.then(() => this._schemaCollection())
|
.then(() => this._schemaCollection())
|
||||||
.then((schemaCollection) => schemaCollection.insertSchema(mongoObject))
|
.then(schemaCollection => schemaCollection.insertSchema(mongoObject))
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
addFieldIfNotExists(
|
addFieldIfNotExists(
|
||||||
@@ -361,11 +366,11 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
type: any
|
type: any
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
return this._schemaCollection()
|
return this._schemaCollection()
|
||||||
.then((schemaCollection) =>
|
.then(schemaCollection =>
|
||||||
schemaCollection.addFieldIfNotExists(className, fieldName, type)
|
schemaCollection.addFieldIfNotExists(className, fieldName, type)
|
||||||
)
|
)
|
||||||
.then(() => this.createIndexesIfNeeded(className, fieldName, type))
|
.then(() => this.createIndexesIfNeeded(className, fieldName, type))
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drops a collection. Resolves with true if it was a Parse Schema (eg. _User, Custom, etc.)
|
// Drops a collection. Resolves with true if it was a Parse Schema (eg. _User, Custom, etc.)
|
||||||
@@ -373,8 +378,8 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
deleteClass(className: string) {
|
deleteClass(className: string) {
|
||||||
return (
|
return (
|
||||||
this._adaptiveCollection(className)
|
this._adaptiveCollection(className)
|
||||||
.then((collection) => collection.drop())
|
.then(collection => collection.drop())
|
||||||
.catch((error) => {
|
.catch(error => {
|
||||||
// 'ns not found' means collection was already gone. Ignore deletion attempt.
|
// 'ns not found' means collection was already gone. Ignore deletion attempt.
|
||||||
if (error.message == 'ns not found') {
|
if (error.message == 'ns not found') {
|
||||||
return;
|
return;
|
||||||
@@ -383,17 +388,17 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
})
|
})
|
||||||
// We've dropped the collection, now remove the _SCHEMA document
|
// We've dropped the collection, now remove the _SCHEMA document
|
||||||
.then(() => this._schemaCollection())
|
.then(() => this._schemaCollection())
|
||||||
.then((schemaCollection) =>
|
.then(schemaCollection =>
|
||||||
schemaCollection.findAndDeleteSchema(className)
|
schemaCollection.findAndDeleteSchema(className)
|
||||||
)
|
)
|
||||||
.catch((err) => this.handleError(err))
|
.catch(err => this.handleError(err))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteAllClasses(fast: boolean) {
|
deleteAllClasses(fast: boolean) {
|
||||||
return storageAdapterAllCollections(this).then((collections) =>
|
return storageAdapterAllCollections(this).then(collections =>
|
||||||
Promise.all(
|
Promise.all(
|
||||||
collections.map((collection) =>
|
collections.map(collection =>
|
||||||
fast ? collection.deleteMany({}) : collection.drop()
|
fast ? collection.deleteMany({}) : collection.drop()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -421,7 +426,7 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
|
|
||||||
// Returns a Promise.
|
// Returns a Promise.
|
||||||
deleteFields(className: string, schema: SchemaType, fieldNames: string[]) {
|
deleteFields(className: string, schema: SchemaType, fieldNames: string[]) {
|
||||||
const mongoFormatNames = fieldNames.map((fieldName) => {
|
const mongoFormatNames = fieldNames.map(fieldName => {
|
||||||
if (schema.fields[fieldName].type === 'Pointer') {
|
if (schema.fields[fieldName].type === 'Pointer') {
|
||||||
return `_p_${fieldName}`;
|
return `_p_${fieldName}`;
|
||||||
} else {
|
} else {
|
||||||
@@ -429,7 +434,7 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
const collectionUpdate = { $unset: {} };
|
const collectionUpdate = { $unset: {} };
|
||||||
mongoFormatNames.forEach((name) => {
|
mongoFormatNames.forEach(name => {
|
||||||
collectionUpdate['$unset'][name] = null;
|
collectionUpdate['$unset'][name] = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -439,18 +444,20 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const schemaUpdate = { $unset: {} };
|
const schemaUpdate = { $unset: {} };
|
||||||
fieldNames.forEach((name) => {
|
fieldNames.forEach(name => {
|
||||||
schemaUpdate['$unset'][name] = null;
|
schemaUpdate['$unset'][name] = null;
|
||||||
schemaUpdate['$unset'][`_metadata.fields_options.${name}`] = null;
|
schemaUpdate['$unset'][`_metadata.fields_options.${name}`] = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
return this._adaptiveCollection(className)
|
return this._adaptiveCollection(className)
|
||||||
.then((collection) => collection.updateMany(collectionFilter, collectionUpdate))
|
.then(collection =>
|
||||||
|
collection.updateMany(collectionFilter, collectionUpdate)
|
||||||
|
)
|
||||||
.then(() => this._schemaCollection())
|
.then(() => this._schemaCollection())
|
||||||
.then((schemaCollection) =>
|
.then(schemaCollection =>
|
||||||
schemaCollection.updateSchema(className, schemaUpdate)
|
schemaCollection.updateSchema(className, schemaUpdate)
|
||||||
)
|
)
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a promise for all schemas known to this adapter, in Parse format. In case the
|
// Return a promise for all schemas known to this adapter, in Parse format. In case the
|
||||||
@@ -458,10 +465,10 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
// rejection reason are TBD.
|
// rejection reason are TBD.
|
||||||
getAllClasses(): Promise<StorageClass[]> {
|
getAllClasses(): Promise<StorageClass[]> {
|
||||||
return this._schemaCollection()
|
return this._schemaCollection()
|
||||||
.then((schemasCollection) =>
|
.then(schemasCollection =>
|
||||||
schemasCollection._fetchAllSchemasFrom_SCHEMA()
|
schemasCollection._fetchAllSchemasFrom_SCHEMA()
|
||||||
)
|
)
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a promise for the schema with the given name, in Parse format. If
|
// Return a promise for the schema with the given name, in Parse format. If
|
||||||
@@ -469,10 +476,10 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
// undefined as the reason.
|
// undefined as the reason.
|
||||||
getClass(className: string): Promise<StorageClass> {
|
getClass(className: string): Promise<StorageClass> {
|
||||||
return this._schemaCollection()
|
return this._schemaCollection()
|
||||||
.then((schemasCollection) =>
|
.then(schemasCollection =>
|
||||||
schemasCollection._fetchOneSchemaFrom_SCHEMA(className)
|
schemasCollection._fetchOneSchemaFrom_SCHEMA(className)
|
||||||
)
|
)
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: As yet not particularly well specified. Creates an object. Maybe shouldn't even need the schema,
|
// TODO: As yet not particularly well specified. Creates an object. Maybe shouldn't even need the schema,
|
||||||
@@ -491,10 +498,10 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
schema
|
schema
|
||||||
);
|
);
|
||||||
return this._adaptiveCollection(className)
|
return this._adaptiveCollection(className)
|
||||||
.then((collection) =>
|
.then(collection =>
|
||||||
collection.insertOne(mongoObject, transactionalSession)
|
collection.insertOne(mongoObject, transactionalSession)
|
||||||
)
|
)
|
||||||
.catch((error) => {
|
.catch(error => {
|
||||||
if (error.code === 11000) {
|
if (error.code === 11000) {
|
||||||
// Duplicate value
|
// Duplicate value
|
||||||
const err = new Parse.Error(
|
const err = new Parse.Error(
|
||||||
@@ -514,7 +521,7 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
}
|
}
|
||||||
throw error;
|
throw error;
|
||||||
})
|
})
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all objects that match the given Parse Query.
|
// Remove all objects that match the given Parse Query.
|
||||||
@@ -528,11 +535,11 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
) {
|
) {
|
||||||
schema = convertParseSchemaToMongoSchema(schema);
|
schema = convertParseSchemaToMongoSchema(schema);
|
||||||
return this._adaptiveCollection(className)
|
return this._adaptiveCollection(className)
|
||||||
.then((collection) => {
|
.then(collection => {
|
||||||
const mongoWhere = transformWhere(className, query, schema);
|
const mongoWhere = transformWhere(className, query, schema);
|
||||||
return collection.deleteMany(mongoWhere, transactionalSession);
|
return collection.deleteMany(mongoWhere, transactionalSession);
|
||||||
})
|
})
|
||||||
.catch((err) => this.handleError(err))
|
.catch(err => this.handleError(err))
|
||||||
.then(
|
.then(
|
||||||
({ result }) => {
|
({ result }) => {
|
||||||
if (result.n === 0) {
|
if (result.n === 0) {
|
||||||
@@ -564,10 +571,10 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
const mongoUpdate = transformUpdate(className, update, schema);
|
const mongoUpdate = transformUpdate(className, update, schema);
|
||||||
const mongoWhere = transformWhere(className, query, schema);
|
const mongoWhere = transformWhere(className, query, schema);
|
||||||
return this._adaptiveCollection(className)
|
return this._adaptiveCollection(className)
|
||||||
.then((collection) =>
|
.then(collection =>
|
||||||
collection.updateMany(mongoWhere, mongoUpdate, transactionalSession)
|
collection.updateMany(mongoWhere, mongoUpdate, transactionalSession)
|
||||||
)
|
)
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Atomically finds and updates an object based on query.
|
// Atomically finds and updates an object based on query.
|
||||||
@@ -583,16 +590,14 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
const mongoUpdate = transformUpdate(className, update, schema);
|
const mongoUpdate = transformUpdate(className, update, schema);
|
||||||
const mongoWhere = transformWhere(className, query, schema);
|
const mongoWhere = transformWhere(className, query, schema);
|
||||||
return this._adaptiveCollection(className)
|
return this._adaptiveCollection(className)
|
||||||
.then((collection) =>
|
.then(collection =>
|
||||||
collection._mongoCollection.findOneAndUpdate(mongoWhere, mongoUpdate, {
|
collection._mongoCollection.findOneAndUpdate(mongoWhere, mongoUpdate, {
|
||||||
returnOriginal: false,
|
returnOriginal: false,
|
||||||
session: transactionalSession || undefined,
|
session: transactionalSession || undefined,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.then((result) =>
|
.then(result => mongoObjectToParseObject(className, result.value, schema))
|
||||||
mongoObjectToParseObject(className, result.value, schema)
|
.catch(error => {
|
||||||
)
|
|
||||||
.catch((error) => {
|
|
||||||
if (error.code === 11000) {
|
if (error.code === 11000) {
|
||||||
throw new Parse.Error(
|
throw new Parse.Error(
|
||||||
Parse.Error.DUPLICATE_VALUE,
|
Parse.Error.DUPLICATE_VALUE,
|
||||||
@@ -601,7 +606,7 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
}
|
}
|
||||||
throw error;
|
throw error;
|
||||||
})
|
})
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hopefully we can get rid of this. It's only used for config and hooks.
|
// Hopefully we can get rid of this. It's only used for config and hooks.
|
||||||
@@ -616,10 +621,10 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
const mongoUpdate = transformUpdate(className, update, schema);
|
const mongoUpdate = transformUpdate(className, update, schema);
|
||||||
const mongoWhere = transformWhere(className, query, schema);
|
const mongoWhere = transformWhere(className, query, schema);
|
||||||
return this._adaptiveCollection(className)
|
return this._adaptiveCollection(className)
|
||||||
.then((collection) =>
|
.then(collection =>
|
||||||
collection.upsertOne(mongoWhere, mongoUpdate, transactionalSession)
|
collection.upsertOne(mongoWhere, mongoUpdate, transactionalSession)
|
||||||
)
|
)
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Executes a find. Accepts: className, query in Parse format, and { skip, limit, sort }.
|
// Executes a find. Accepts: className, query in Parse format, and { skip, limit, sort }.
|
||||||
@@ -667,7 +672,7 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
readPreference = this._parseReadPreference(readPreference);
|
readPreference = this._parseReadPreference(readPreference);
|
||||||
return this.createTextIndexesIfNeeded(className, query, schema)
|
return this.createTextIndexesIfNeeded(className, query, schema)
|
||||||
.then(() => this._adaptiveCollection(className))
|
.then(() => this._adaptiveCollection(className))
|
||||||
.then((collection) =>
|
.then(collection =>
|
||||||
collection.find(mongoWhere, {
|
collection.find(mongoWhere, {
|
||||||
skip,
|
skip,
|
||||||
limit,
|
limit,
|
||||||
@@ -680,15 +685,15 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
explain,
|
explain,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.then((objects) => {
|
.then(objects => {
|
||||||
if (explain) {
|
if (explain) {
|
||||||
return objects;
|
return objects;
|
||||||
}
|
}
|
||||||
return objects.map((object) =>
|
return objects.map(object =>
|
||||||
mongoObjectToParseObject(className, object, schema)
|
mongoObjectToParseObject(className, object, schema)
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
ensureIndex(
|
ensureIndex(
|
||||||
@@ -697,20 +702,22 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
fieldNames: string[],
|
fieldNames: string[],
|
||||||
indexName: ?string,
|
indexName: ?string,
|
||||||
caseInsensitive: boolean = false,
|
caseInsensitive: boolean = false,
|
||||||
options?: Object = {},
|
options?: Object = {}
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
schema = convertParseSchemaToMongoSchema(schema);
|
schema = convertParseSchemaToMongoSchema(schema);
|
||||||
const indexCreationRequest = {};
|
const indexCreationRequest = {};
|
||||||
const mongoFieldNames = fieldNames.map((fieldName) =>
|
const mongoFieldNames = fieldNames.map(fieldName =>
|
||||||
transformKey(className, fieldName, schema)
|
transformKey(className, fieldName, schema)
|
||||||
);
|
);
|
||||||
mongoFieldNames.forEach((fieldName) => {
|
mongoFieldNames.forEach(fieldName => {
|
||||||
indexCreationRequest[fieldName] = options.indexType !== undefined ? options.indexType : 1;
|
indexCreationRequest[fieldName] =
|
||||||
|
options.indexType !== undefined ? options.indexType : 1;
|
||||||
});
|
});
|
||||||
|
|
||||||
const defaultOptions: Object = { background: true, sparse: true };
|
const defaultOptions: Object = { background: true, sparse: true };
|
||||||
const indexNameOptions: Object = indexName ? { name: indexName } : {};
|
const indexNameOptions: Object = indexName ? { name: indexName } : {};
|
||||||
const ttlOptions: Object = options.ttl !== undefined ? { expireAfterSeconds: options.ttl } : {};
|
const ttlOptions: Object =
|
||||||
|
options.ttl !== undefined ? { expireAfterSeconds: options.ttl } : {};
|
||||||
const caseInsensitiveOptions: Object = caseInsensitive
|
const caseInsensitiveOptions: Object = caseInsensitive
|
||||||
? { collation: MongoCollection.caseInsensitiveCollation() }
|
? { collation: MongoCollection.caseInsensitiveCollation() }
|
||||||
: {};
|
: {};
|
||||||
@@ -723,16 +730,16 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
|
|
||||||
return this._adaptiveCollection(className)
|
return this._adaptiveCollection(className)
|
||||||
.then(
|
.then(
|
||||||
(collection) =>
|
collection =>
|
||||||
new Promise((resolve, reject) =>
|
new Promise((resolve, reject) =>
|
||||||
collection._mongoCollection.createIndex(
|
collection._mongoCollection.createIndex(
|
||||||
indexCreationRequest,
|
indexCreationRequest,
|
||||||
indexOptions,
|
indexOptions,
|
||||||
(error) => (error ? reject(error) : resolve())
|
error => (error ? reject(error) : resolve())
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a unique index. Unique indexes on nullable fields are not allowed. Since we don't
|
// Create a unique index. Unique indexes on nullable fields are not allowed. Since we don't
|
||||||
@@ -747,17 +754,17 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
) {
|
) {
|
||||||
schema = convertParseSchemaToMongoSchema(schema);
|
schema = convertParseSchemaToMongoSchema(schema);
|
||||||
const indexCreationRequest = {};
|
const indexCreationRequest = {};
|
||||||
const mongoFieldNames = fieldNames.map((fieldName) =>
|
const mongoFieldNames = fieldNames.map(fieldName =>
|
||||||
transformKey(className, fieldName, schema)
|
transformKey(className, fieldName, schema)
|
||||||
);
|
);
|
||||||
mongoFieldNames.forEach((fieldName) => {
|
mongoFieldNames.forEach(fieldName => {
|
||||||
indexCreationRequest[fieldName] = 1;
|
indexCreationRequest[fieldName] = 1;
|
||||||
});
|
});
|
||||||
return this._adaptiveCollection(className)
|
return this._adaptiveCollection(className)
|
||||||
.then((collection) =>
|
.then(collection =>
|
||||||
collection._ensureSparseUniqueIndexInBackground(indexCreationRequest)
|
collection._ensureSparseUniqueIndexInBackground(indexCreationRequest)
|
||||||
)
|
)
|
||||||
.catch((error) => {
|
.catch(error => {
|
||||||
if (error.code === 11000) {
|
if (error.code === 11000) {
|
||||||
throw new Parse.Error(
|
throw new Parse.Error(
|
||||||
Parse.Error.DUPLICATE_VALUE,
|
Parse.Error.DUPLICATE_VALUE,
|
||||||
@@ -766,18 +773,18 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
}
|
}
|
||||||
throw error;
|
throw error;
|
||||||
})
|
})
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used in tests
|
// Used in tests
|
||||||
_rawFind(className: string, query: QueryType) {
|
_rawFind(className: string, query: QueryType) {
|
||||||
return this._adaptiveCollection(className)
|
return this._adaptiveCollection(className)
|
||||||
.then((collection) =>
|
.then(collection =>
|
||||||
collection.find(query, {
|
collection.find(query, {
|
||||||
maxTimeMS: this._maxTimeMS,
|
maxTimeMS: this._maxTimeMS,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Executes a count.
|
// Executes a count.
|
||||||
@@ -791,14 +798,14 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
schema = convertParseSchemaToMongoSchema(schema);
|
schema = convertParseSchemaToMongoSchema(schema);
|
||||||
readPreference = this._parseReadPreference(readPreference);
|
readPreference = this._parseReadPreference(readPreference);
|
||||||
return this._adaptiveCollection(className)
|
return this._adaptiveCollection(className)
|
||||||
.then((collection) =>
|
.then(collection =>
|
||||||
collection.count(transformWhere(className, query, schema, true), {
|
collection.count(transformWhere(className, query, schema, true), {
|
||||||
maxTimeMS: this._maxTimeMS,
|
maxTimeMS: this._maxTimeMS,
|
||||||
readPreference,
|
readPreference,
|
||||||
hint,
|
hint,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
distinct(
|
distinct(
|
||||||
@@ -813,22 +820,22 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
const transformField = transformKey(className, fieldName, schema);
|
const transformField = transformKey(className, fieldName, schema);
|
||||||
|
|
||||||
return this._adaptiveCollection(className)
|
return this._adaptiveCollection(className)
|
||||||
.then((collection) =>
|
.then(collection =>
|
||||||
collection.distinct(
|
collection.distinct(
|
||||||
transformField,
|
transformField,
|
||||||
transformWhere(className, query, schema)
|
transformWhere(className, query, schema)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.then((objects) => {
|
.then(objects => {
|
||||||
objects = objects.filter((obj) => obj != null);
|
objects = objects.filter(obj => obj != null);
|
||||||
return objects.map((object) => {
|
return objects.map(object => {
|
||||||
if (isPointerField) {
|
if (isPointerField) {
|
||||||
return transformPointerString(schema, fieldName, object);
|
return transformPointerString(schema, fieldName, object);
|
||||||
}
|
}
|
||||||
return mongoObjectToParseObject(className, object, schema);
|
return mongoObjectToParseObject(className, object, schema);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
aggregate(
|
aggregate(
|
||||||
@@ -840,7 +847,7 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
explain?: boolean
|
explain?: boolean
|
||||||
) {
|
) {
|
||||||
let isPointerField = false;
|
let isPointerField = false;
|
||||||
pipeline = pipeline.map((stage) => {
|
pipeline = pipeline.map(stage => {
|
||||||
if (stage.$group) {
|
if (stage.$group) {
|
||||||
stage.$group = this._parseAggregateGroupArgs(schema, stage.$group);
|
stage.$group = this._parseAggregateGroupArgs(schema, stage.$group);
|
||||||
if (
|
if (
|
||||||
@@ -870,7 +877,7 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
});
|
});
|
||||||
readPreference = this._parseReadPreference(readPreference);
|
readPreference = this._parseReadPreference(readPreference);
|
||||||
return this._adaptiveCollection(className)
|
return this._adaptiveCollection(className)
|
||||||
.then((collection) =>
|
.then(collection =>
|
||||||
collection.aggregate(pipeline, {
|
collection.aggregate(pipeline, {
|
||||||
readPreference,
|
readPreference,
|
||||||
maxTimeMS: this._maxTimeMS,
|
maxTimeMS: this._maxTimeMS,
|
||||||
@@ -878,8 +885,8 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
explain,
|
explain,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.then((results) => {
|
.then(results => {
|
||||||
results.forEach((result) => {
|
results.forEach(result => {
|
||||||
if (Object.prototype.hasOwnProperty.call(result, '_id')) {
|
if (Object.prototype.hasOwnProperty.call(result, '_id')) {
|
||||||
if (isPointerField && result._id) {
|
if (isPointerField && result._id) {
|
||||||
result._id = result._id.split('$')[1];
|
result._id = result._id.split('$')[1];
|
||||||
@@ -898,12 +905,12 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
});
|
});
|
||||||
return results;
|
return results;
|
||||||
})
|
})
|
||||||
.then((objects) =>
|
.then(objects =>
|
||||||
objects.map((object) =>
|
objects.map(object =>
|
||||||
mongoObjectToParseObject(className, object, schema)
|
mongoObjectToParseObject(className, object, schema)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function will recursively traverse the pipeline and convert any Pointer or Date columns.
|
// This function will recursively traverse the pipeline and convert any Pointer or Date columns.
|
||||||
@@ -929,7 +936,7 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
if (pipeline === null) {
|
if (pipeline === null) {
|
||||||
return null;
|
return null;
|
||||||
} else if (Array.isArray(pipeline)) {
|
} else if (Array.isArray(pipeline)) {
|
||||||
return pipeline.map((value) => this._parseAggregateArgs(schema, value));
|
return pipeline.map(value => this._parseAggregateArgs(schema, value));
|
||||||
} else if (typeof pipeline === 'object') {
|
} else if (typeof pipeline === 'object') {
|
||||||
const returnValue = {};
|
const returnValue = {};
|
||||||
for (const field in pipeline) {
|
for (const field in pipeline) {
|
||||||
@@ -1004,7 +1011,7 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
// updatedAt or objectId and change it accordingly.
|
// updatedAt or objectId and change it accordingly.
|
||||||
_parseAggregateGroupArgs(schema: any, pipeline: any): any {
|
_parseAggregateGroupArgs(schema: any, pipeline: any): any {
|
||||||
if (Array.isArray(pipeline)) {
|
if (Array.isArray(pipeline)) {
|
||||||
return pipeline.map((value) =>
|
return pipeline.map(value =>
|
||||||
this._parseAggregateGroupArgs(schema, value)
|
this._parseAggregateGroupArgs(schema, value)
|
||||||
);
|
);
|
||||||
} else if (typeof pipeline === 'object') {
|
} else if (typeof pipeline === 'object') {
|
||||||
@@ -1084,14 +1091,14 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
|
|
||||||
createIndex(className: string, index: any) {
|
createIndex(className: string, index: any) {
|
||||||
return this._adaptiveCollection(className)
|
return this._adaptiveCollection(className)
|
||||||
.then((collection) => collection._mongoCollection.createIndex(index))
|
.then(collection => collection._mongoCollection.createIndex(index))
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
createIndexes(className: string, indexes: any) {
|
createIndexes(className: string, indexes: any) {
|
||||||
return this._adaptiveCollection(className)
|
return this._adaptiveCollection(className)
|
||||||
.then((collection) => collection._mongoCollection.createIndexes(indexes))
|
.then(collection => collection._mongoCollection.createIndexes(indexes))
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
createIndexesIfNeeded(className: string, fieldName: string, type: any) {
|
createIndexesIfNeeded(className: string, fieldName: string, type: any) {
|
||||||
@@ -1129,7 +1136,7 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
textIndex,
|
textIndex,
|
||||||
existingIndexes,
|
existingIndexes,
|
||||||
schema.fields
|
schema.fields
|
||||||
).catch((error) => {
|
).catch(error => {
|
||||||
if (error.code === 85) {
|
if (error.code === 85) {
|
||||||
// Index exist with different options
|
// Index exist with different options
|
||||||
return this.setIndexesFromMongo(className);
|
return this.setIndexesFromMongo(className);
|
||||||
@@ -1142,31 +1149,31 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
|
|
||||||
getIndexes(className: string) {
|
getIndexes(className: string) {
|
||||||
return this._adaptiveCollection(className)
|
return this._adaptiveCollection(className)
|
||||||
.then((collection) => collection._mongoCollection.indexes())
|
.then(collection => collection._mongoCollection.indexes())
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
dropIndex(className: string, index: any) {
|
dropIndex(className: string, index: any) {
|
||||||
return this._adaptiveCollection(className)
|
return this._adaptiveCollection(className)
|
||||||
.then((collection) => collection._mongoCollection.dropIndex(index))
|
.then(collection => collection._mongoCollection.dropIndex(index))
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
dropAllIndexes(className: string) {
|
dropAllIndexes(className: string) {
|
||||||
return this._adaptiveCollection(className)
|
return this._adaptiveCollection(className)
|
||||||
.then((collection) => collection._mongoCollection.dropIndexes())
|
.then(collection => collection._mongoCollection.dropIndexes())
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSchemaWithIndexes(): Promise<any> {
|
updateSchemaWithIndexes(): Promise<any> {
|
||||||
return this.getAllClasses()
|
return this.getAllClasses()
|
||||||
.then((classes) => {
|
.then(classes => {
|
||||||
const promises = classes.map((schema) => {
|
const promises = classes.map(schema => {
|
||||||
return this.setIndexesFromMongo(schema.className);
|
return this.setIndexesFromMongo(schema.className);
|
||||||
});
|
});
|
||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
})
|
})
|
||||||
.catch((err) => this.handleError(err));
|
.catch(err => this.handleError(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
createTransactionalSession(): Promise<any> {
|
createTransactionalSession(): Promise<any> {
|
||||||
|
|||||||
Reference in New Issue
Block a user