Postgres adapter (#2012)
* Remove adaptiveCollection * Remove an adaptiveCollection use * Remove an adaptiveCollection * make adaptiveCollection private * Remove collection from mongoadapter * Move schema collection usage into mongo adapter * stop relying on mongo format for removing join tables * reduce usage of schemaCollection * remove uses of _collection * Move CLP setting into mongo adapter * remove all uses of schemaCollection * make schemaCollection private * remove transform from schemaCollection * rename some stuff * Tweak paramaters and stuff * reorder some params * reorder find() arguments * finishsh touching up argument order * Accept a database adapter as a parameter * First passing test with postgres! * Actually use the provided className * index on unique-indexes: c454180 Revert "Log objects rather than JSON stringified objects (#1922)" * Start dealing with test shittyness * Make specific server config for tests async * Fix email validation * Fix broken cloud code * Save callback to variable * undo * Fix tests * Setup travis * fix travis maybe * try removing db user * indentation? * remove postgres version setting * sudo maybe? * use postgres username * fix check for _PushStatus * excludes * remove db=mongo * allow postgres to fail * Fix allow failure * postgres 9.4 * Remove mongo implementations and fix test * Fix test leaving behind connections
This commit is contained in:
@@ -69,25 +69,19 @@ export class MongoStorageAdapter {
|
||||
return this.connectionPromise;
|
||||
}
|
||||
|
||||
collection(name: string) {
|
||||
return this.connect().then(() => {
|
||||
return this.database.collection(name);
|
||||
});
|
||||
}
|
||||
|
||||
adaptiveCollection(name: string) {
|
||||
_adaptiveCollection(name: string) {
|
||||
return this.connect()
|
||||
.then(() => this.database.collection(this._collectionPrefix + name))
|
||||
.then(rawCollection => new MongoCollection(rawCollection));
|
||||
}
|
||||
|
||||
schemaCollection() {
|
||||
_schemaCollection() {
|
||||
return this.connect()
|
||||
.then(() => this.adaptiveCollection(MongoSchemaCollectionName))
|
||||
.then(() => this._adaptiveCollection(MongoSchemaCollectionName))
|
||||
.then(collection => new MongoSchemaCollection(collection));
|
||||
}
|
||||
|
||||
collectionExists(name: string) {
|
||||
classExists(name) {
|
||||
return this.connect().then(() => {
|
||||
return this.database.listCollections({ name: this._collectionPrefix + name }).toArray();
|
||||
}).then(collections => {
|
||||
@@ -95,22 +89,42 @@ export class MongoStorageAdapter {
|
||||
});
|
||||
}
|
||||
|
||||
// Deletes a schema. Resolve if successful. If the schema doesn't
|
||||
// exist, resolve with undefined. If schema exists, but can't be deleted for some other reason,
|
||||
// reject with INTERNAL_SERVER_ERROR.
|
||||
deleteOneSchema(className: string) {
|
||||
return this.collection(this._collectionPrefix + className).then(collection => collection.drop())
|
||||
setClassLevelPermissions(className, CLPs) {
|
||||
return this._schemaCollection()
|
||||
.then(schemaCollection => schemaCollection.updateSchema(className, {
|
||||
$set: { _metadata: { class_permissions: CLPs } }
|
||||
}));
|
||||
}
|
||||
|
||||
createClass(className, schema) {
|
||||
return this._schemaCollection()
|
||||
.then(schemaCollection => schemaCollection.addSchema(className, schema.fields, schema.classLevelPermissions));
|
||||
}
|
||||
|
||||
addFieldIfNotExists(className, fieldName, type) {
|
||||
return this._schemaCollection()
|
||||
.then(schemaCollection => schemaCollection.addFieldIfNotExists(className, fieldName, type));
|
||||
}
|
||||
|
||||
// Drops a collection. Resolves with true if it was a Parse Schema (eg. _User, Custom, etc.)
|
||||
// and resolves with false if it wasn't (eg. a join table). Rejects if deletion was impossible.
|
||||
deleteClass(className) {
|
||||
return this._adaptiveCollection(className)
|
||||
.then(collection => collection.drop())
|
||||
.catch(error => {
|
||||
// 'ns not found' means collection was already gone. Ignore deletion attempt.
|
||||
if (error.message == 'ns not found') {
|
||||
return;
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
})
|
||||
// We've dropped the collection, now remove the _SCHEMA document
|
||||
.then(() => this._schemaCollection())
|
||||
.then(schemaCollection => schemaCollection.findAndDeleteSchema(className))
|
||||
}
|
||||
|
||||
// Delete all data known to this adatper. Used for testing.
|
||||
deleteAllSchemas() {
|
||||
deleteAllClasses() {
|
||||
return storageAdapterAllCollections(this)
|
||||
.then(collections => Promise.all(collections.map(collection => collection.drop())));
|
||||
}
|
||||
@@ -135,9 +149,14 @@ export class MongoStorageAdapter {
|
||||
// may do so.
|
||||
|
||||
// Returns a Promise.
|
||||
deleteFields(className: string, fieldNames, pointerFieldNames) {
|
||||
const nonPointerFieldNames = _.difference(fieldNames, pointerFieldNames);
|
||||
const mongoFormatNames = nonPointerFieldNames.concat(pointerFieldNames.map(name => `_p_${name}`));
|
||||
deleteFields(className, schema, fieldNames) {
|
||||
const mongoFormatNames = fieldNames.map(fieldName => {
|
||||
if (schema.fields[fieldName].type === 'Pointer') {
|
||||
return `_p_${fieldName}`
|
||||
} else {
|
||||
return fieldName;
|
||||
}
|
||||
});
|
||||
const collectionUpdate = { '$unset' : {} };
|
||||
mongoFormatNames.forEach(name => {
|
||||
collectionUpdate['$unset'][name] = null;
|
||||
@@ -148,33 +167,33 @@ export class MongoStorageAdapter {
|
||||
schemaUpdate['$unset'][name] = null;
|
||||
});
|
||||
|
||||
return this.adaptiveCollection(className)
|
||||
return this._adaptiveCollection(className)
|
||||
.then(collection => collection.updateMany({}, collectionUpdate))
|
||||
.then(updateResult => this.schemaCollection())
|
||||
.then(() => this._schemaCollection())
|
||||
.then(schemaCollection => schemaCollection.updateSchema(className, schemaUpdate));
|
||||
}
|
||||
|
||||
// Return a promise for all schemas known to this adapter, in Parse format. In case the
|
||||
// schemas cannot be retrieved, returns a promise that rejects. Requirements for the
|
||||
// rejection reason are TBD.
|
||||
getAllSchemas() {
|
||||
return this.schemaCollection().then(schemasCollection => schemasCollection._fetchAllSchemasFrom_SCHEMA());
|
||||
getAllClasses() {
|
||||
return this._schemaCollection().then(schemasCollection => schemasCollection._fetchAllSchemasFrom_SCHEMA());
|
||||
}
|
||||
|
||||
// Return a promise for the schema with the given name, in Parse format. If
|
||||
// this adapter doesn't know about the schema, return a promise that rejects with
|
||||
// undefined as the reason.
|
||||
getOneSchema(className) {
|
||||
return this.schemaCollection()
|
||||
getClass(className) {
|
||||
return this._schemaCollection()
|
||||
.then(schemasCollection => schemasCollection._fechOneSchemaFrom_SCHEMA(className));
|
||||
}
|
||||
|
||||
// TODO: As yet not particularly well specified. Creates an object. Maybe shouldn't even need the schema,
|
||||
// and should infer from the type. Or maybe does need the schema for validations. Or maybe needs
|
||||
// the schem only for the legacy mongo format. We'll figure that out later.
|
||||
createObject(className, object, schema) {
|
||||
createObject(className, schema, object) {
|
||||
const mongoObject = parseObjectToMongoObjectForCreate(className, object, schema);
|
||||
return this.adaptiveCollection(className)
|
||||
return this._adaptiveCollection(className)
|
||||
.then(collection => collection.insertOne(mongoObject))
|
||||
.catch(error => {
|
||||
if (error.code === 11000) { // Duplicate value
|
||||
@@ -188,8 +207,8 @@ export class MongoStorageAdapter {
|
||||
// Remove all objects that match the given Parse Query.
|
||||
// If no objects match, reject with OBJECT_NOT_FOUND. If objects are found and deleted, resolve with undefined.
|
||||
// If there is some other error, reject with INTERNAL_SERVER_ERROR.
|
||||
deleteObjectsByQuery(className, query, schema) {
|
||||
return this.adaptiveCollection(className)
|
||||
deleteObjectsByQuery(className, schema, query) {
|
||||
return this._adaptiveCollection(className)
|
||||
.then(collection => {
|
||||
let mongoWhere = transformWhere(className, query, schema);
|
||||
return collection.deleteMany(mongoWhere)
|
||||
@@ -205,36 +224,36 @@ export class MongoStorageAdapter {
|
||||
}
|
||||
|
||||
// Apply the update to all objects that match the given Parse Query.
|
||||
updateObjectsByQuery(className, query, schema, update) {
|
||||
updateObjectsByQuery(className, schema, query, update) {
|
||||
const mongoUpdate = transformUpdate(className, update, schema);
|
||||
const mongoWhere = transformWhere(className, query, schema);
|
||||
return this.adaptiveCollection(className)
|
||||
return this._adaptiveCollection(className)
|
||||
.then(collection => collection.updateMany(mongoWhere, mongoUpdate));
|
||||
}
|
||||
|
||||
// Atomically finds and updates an object based on query.
|
||||
// Resolve with the updated object.
|
||||
findOneAndUpdate(className, query, schema, update) {
|
||||
findOneAndUpdate(className, schema, query, update) {
|
||||
const mongoUpdate = transformUpdate(className, update, schema);
|
||||
const mongoWhere = transformWhere(className, query, schema);
|
||||
return this.adaptiveCollection(className)
|
||||
return this._adaptiveCollection(className)
|
||||
.then(collection => collection._mongoCollection.findAndModify(mongoWhere, [], mongoUpdate, { new: true }))
|
||||
.then(result => result.value);
|
||||
}
|
||||
|
||||
// Hopefully we can get rid of this. It's only used for config and hooks.
|
||||
upsertOneObject(className, query, schema, update) {
|
||||
upsertOneObject(className, schema, query, update) {
|
||||
const mongoUpdate = transformUpdate(className, update, schema);
|
||||
const mongoWhere = transformWhere(className, query, schema);
|
||||
return this.adaptiveCollection(className)
|
||||
return this._adaptiveCollection(className)
|
||||
.then(collection => collection.upsertOne(mongoWhere, mongoUpdate));
|
||||
}
|
||||
|
||||
// Executes a find. Accepts: className, query in Parse format, and { skip, limit, sort }.
|
||||
find(className, query, schema, { skip, limit, sort }) {
|
||||
find(className, schema, query, { skip, limit, sort }) {
|
||||
let mongoWhere = transformWhere(className, query, schema);
|
||||
let mongoSort = _.mapKeys(sort, (value, fieldName) => transformKey(className, fieldName, schema));
|
||||
return this.adaptiveCollection(className)
|
||||
return this._adaptiveCollection(className)
|
||||
.then(collection => collection.find(mongoWhere, { skip, limit, sort: mongoSort }))
|
||||
.then(objects => objects.map(object => mongoObjectToParseObject(className, object, schema)));
|
||||
}
|
||||
@@ -244,13 +263,13 @@ export class MongoStorageAdapter {
|
||||
// As such, we shouldn't expose this function to users of parse until we have an out-of-band
|
||||
// Way of determining if a field is nullable. Undefined doesn't count against uniqueness,
|
||||
// which is why we use sparse indexes.
|
||||
ensureUniqueness(className, fieldNames, schema) {
|
||||
ensureUniqueness(className, schema, fieldNames) {
|
||||
let indexCreationRequest = {};
|
||||
let mongoFieldNames = fieldNames.map(fieldName => transformKey(className, fieldName, schema));
|
||||
mongoFieldNames.forEach(fieldName => {
|
||||
indexCreationRequest[fieldName] = 1;
|
||||
});
|
||||
return this.adaptiveCollection(className)
|
||||
return this._adaptiveCollection(className)
|
||||
.then(collection => collection._ensureSparseUniqueIndexInBackground(indexCreationRequest))
|
||||
.catch(error => {
|
||||
if (error.code === 11000) {
|
||||
@@ -263,12 +282,12 @@ export class MongoStorageAdapter {
|
||||
|
||||
// Used in tests
|
||||
_rawFind(className, query) {
|
||||
return this.adaptiveCollection(className).then(collection => collection.find(query));
|
||||
return this._adaptiveCollection(className).then(collection => collection.find(query));
|
||||
}
|
||||
|
||||
// Executs a count.
|
||||
count(className, query, schema) {
|
||||
return this.adaptiveCollection(className)
|
||||
count(className, schema, query) {
|
||||
return this._adaptiveCollection(className)
|
||||
.then(collection => collection.count(transformWhere(className, query, schema)));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user