Merge pull request #698 from ParsePlatform/nlutsenko.database.controller
Rename ExportAdapter to DatabaseController, start splitting Mongo specific logic.
This commit is contained in:
17
spec/DatabaseController.spec.js
Normal file
17
spec/DatabaseController.spec.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
let DatabaseController = require('../src/Controllers/DatabaseController');
|
||||||
|
let MongoStorageAdapter = require('../src/Adapters/Storage/Mongo/MongoStorageAdapter');
|
||||||
|
|
||||||
|
describe('DatabaseController', () => {
|
||||||
|
it('can be constructed', done => {
|
||||||
|
let adapter = new MongoStorageAdapter('mongodb://localhost:27017/test');
|
||||||
|
let databaseController = new DatabaseController(adapter, {
|
||||||
|
collectionPrefix: 'test_'
|
||||||
|
});
|
||||||
|
databaseController.connect().then(done, error => {
|
||||||
|
console.log('error', error.stack);
|
||||||
|
fail();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
var ExportAdapter = require('../src/ExportAdapter');
|
|
||||||
|
|
||||||
describe('ExportAdapter', () => {
|
|
||||||
it('can be constructed', (done) => {
|
|
||||||
var database = new ExportAdapter('mongodb://localhost:27017/test',
|
|
||||||
{
|
|
||||||
collectionPrefix: 'test_'
|
|
||||||
});
|
|
||||||
database.connect().then(done, (error) => {
|
|
||||||
console.log('error', error.stack);
|
|
||||||
fail();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
@@ -520,11 +520,11 @@ describe('Schema', () => {
|
|||||||
return obj2.save();
|
return obj2.save();
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
config.database.db.collection('test__Join:aRelation:HasPointersAndRelations', { strict: true }, (err, coll) => {
|
config.database.adapter.database.collection('test__Join:aRelation:HasPointersAndRelations', { strict: true }, (err, coll) => {
|
||||||
expect(err).toEqual(null);
|
expect(err).toEqual(null);
|
||||||
config.database.loadSchema()
|
config.database.loadSchema()
|
||||||
.then(schema => schema.deleteField('aRelation', 'HasPointersAndRelations', config.database.db, 'test_'))
|
.then(schema => schema.deleteField('aRelation', 'HasPointersAndRelations', config.database.adapter.database, 'test_'))
|
||||||
.then(() => config.database.db.collection('test__Join:aRelation:HasPointersAndRelations', { strict: true }, (err, coll) => {
|
.then(() => config.database.adapter.database.collection('test__Join:aRelation:HasPointersAndRelations', { strict: true }, (err, coll) => {
|
||||||
expect(err).not.toEqual(null);
|
expect(err).not.toEqual(null);
|
||||||
done();
|
done();
|
||||||
}))
|
}))
|
||||||
@@ -538,7 +538,7 @@ describe('Schema', () => {
|
|||||||
var obj2 = hasAllPODobject();
|
var obj2 = hasAllPODobject();
|
||||||
var p = Parse.Object.saveAll([obj1, obj2])
|
var p = Parse.Object.saveAll([obj1, obj2])
|
||||||
.then(() => config.database.loadSchema())
|
.then(() => config.database.loadSchema())
|
||||||
.then(schema => schema.deleteField('aString', 'HasAllPOD', config.database.db, 'test_'))
|
.then(schema => schema.deleteField('aString', 'HasAllPOD', config.database.adapter.database, 'test_'))
|
||||||
.then(() => new Parse.Query('HasAllPOD').get(obj1.id))
|
.then(() => new Parse.Query('HasAllPOD').get(obj1.id))
|
||||||
.then(obj1Reloaded => {
|
.then(obj1Reloaded => {
|
||||||
expect(obj1Reloaded.get('aString')).toEqual(undefined);
|
expect(obj1Reloaded.get('aString')).toEqual(undefined);
|
||||||
@@ -568,7 +568,7 @@ describe('Schema', () => {
|
|||||||
expect(obj1.get('aPointer').id).toEqual(obj1.id);
|
expect(obj1.get('aPointer').id).toEqual(obj1.id);
|
||||||
})
|
})
|
||||||
.then(() => config.database.loadSchema())
|
.then(() => config.database.loadSchema())
|
||||||
.then(schema => schema.deleteField('aPointer', 'NewClass', config.database.db, 'test_'))
|
.then(schema => schema.deleteField('aPointer', 'NewClass', config.database.adapter.database, 'test_'))
|
||||||
.then(() => new Parse.Query('NewClass').get(obj1.id))
|
.then(() => new Parse.Query('NewClass').get(obj1.id))
|
||||||
.then(obj1 => {
|
.then(obj1 => {
|
||||||
expect(obj1.get('aPointer')).toEqual(undefined);
|
expect(obj1.get('aPointer')).toEqual(undefined);
|
||||||
|
|||||||
@@ -710,10 +710,10 @@ describe('schemas', () => {
|
|||||||
}, (error, response, body) => {
|
}, (error, response, body) => {
|
||||||
expect(response.statusCode).toEqual(200);
|
expect(response.statusCode).toEqual(200);
|
||||||
expect(response.body).toEqual({});
|
expect(response.body).toEqual({});
|
||||||
config.database.db.collection('test__Join:aRelation:MyOtherClass', { strict: true }, (err, coll) => {
|
config.database.adapter.database.collection('test__Join:aRelation:MyOtherClass', { strict: true }, (err, coll) => {
|
||||||
//Expect Join table to be gone
|
//Expect Join table to be gone
|
||||||
expect(err).not.toEqual(null);
|
expect(err).not.toEqual(null);
|
||||||
config.database.db.collection('test_MyOtherClass', { strict: true }, (err, coll) => {
|
config.database.adapter.database.collection('test_MyOtherClass', { strict: true }, (err, coll) => {
|
||||||
// Expect data table to be gone
|
// Expect data table to be gone
|
||||||
expect(err).not.toEqual(null);
|
expect(err).not.toEqual(null);
|
||||||
request.get({
|
request.get({
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
// * getFileLocation(config, request, filename)
|
// * getFileLocation(config, request, filename)
|
||||||
//
|
//
|
||||||
// Default is GridStoreAdapter, which requires mongo
|
// Default is GridStoreAdapter, which requires mongo
|
||||||
// and for the API server to be using the ExportAdapter
|
// and for the API server to be using the DatabaseController with Mongo
|
||||||
// database adapter.
|
// database adapter.
|
||||||
|
|
||||||
export class FilesAdapter {
|
export class FilesAdapter {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export class GridStoreAdapter extends FilesAdapter {
|
|||||||
// Returns a promise
|
// Returns a promise
|
||||||
createFile(config, filename, data) {
|
createFile(config, filename, data) {
|
||||||
return config.database.connect().then(() => {
|
return config.database.connect().then(() => {
|
||||||
let gridStore = new GridStore(config.database.db, filename, 'w');
|
let gridStore = new GridStore(config.database.adapter.database, filename, 'w');
|
||||||
return gridStore.open();
|
return gridStore.open();
|
||||||
}).then((gridStore) => {
|
}).then((gridStore) => {
|
||||||
return gridStore.write(data);
|
return gridStore.write(data);
|
||||||
@@ -22,7 +22,7 @@ export class GridStoreAdapter extends FilesAdapter {
|
|||||||
|
|
||||||
deleteFile(config, filename) {
|
deleteFile(config, filename) {
|
||||||
return config.database.connect().then(() => {
|
return config.database.connect().then(() => {
|
||||||
let gridStore = new GridStore(config.database.db, filename, 'w');
|
let gridStore = new GridStore(config.database.adapter.database, filename, 'w');
|
||||||
return gridStore.open();
|
return gridStore.open();
|
||||||
}).then((gridStore) => {
|
}).then((gridStore) => {
|
||||||
return gridStore.unlink();
|
return gridStore.unlink();
|
||||||
@@ -33,9 +33,9 @@ export class GridStoreAdapter extends FilesAdapter {
|
|||||||
|
|
||||||
getFileData(config, filename) {
|
getFileData(config, filename) {
|
||||||
return config.database.connect().then(() => {
|
return config.database.connect().then(() => {
|
||||||
return GridStore.exist(config.database.db, filename);
|
return GridStore.exist(config.database.adapter.database, filename);
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
let gridStore = new GridStore(config.database.db, filename, 'r');
|
let gridStore = new GridStore(config.database.adapter.database, filename, 'r');
|
||||||
return gridStore.open();
|
return gridStore.open();
|
||||||
}).then((gridStore) => {
|
}).then((gridStore) => {
|
||||||
return gridStore.read();
|
return gridStore.read();
|
||||||
|
|||||||
49
src/Adapters/Storage/Mongo/MongoStorageAdapter.js
Normal file
49
src/Adapters/Storage/Mongo/MongoStorageAdapter.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
|
||||||
|
let mongodb = require('mongodb');
|
||||||
|
let MongoClient = mongodb.MongoClient;
|
||||||
|
|
||||||
|
export class MongoStorageAdapter {
|
||||||
|
// Private
|
||||||
|
_uri: string;
|
||||||
|
// Public
|
||||||
|
connectionPromise;
|
||||||
|
database;
|
||||||
|
|
||||||
|
constructor(uri: string) {
|
||||||
|
this._uri = uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
if (this.connectionPromise) {
|
||||||
|
return this.connectionPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.connectionPromise = MongoClient.connect(this._uri).then(database => {
|
||||||
|
this.database = database;
|
||||||
|
});
|
||||||
|
return this.connectionPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
collection(name: string) {
|
||||||
|
return this.connect().then(() => {
|
||||||
|
return this.database.collection(name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used for testing only right now.
|
||||||
|
collectionsContaining(match: string) {
|
||||||
|
return this.connect().then(() => {
|
||||||
|
return this.database.collections();
|
||||||
|
}).then(collections => {
|
||||||
|
return collections.filter(collection => {
|
||||||
|
if (collection.namespace.match(/\.system\./)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (collection.collectionName.indexOf(match) == 0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MongoStorageAdapter;
|
||||||
|
module.exports = MongoStorageAdapter; // Required for tests
|
||||||
@@ -2,18 +2,17 @@
|
|||||||
// Parse database.
|
// Parse database.
|
||||||
|
|
||||||
var mongodb = require('mongodb');
|
var mongodb = require('mongodb');
|
||||||
var MongoClient = mongodb.MongoClient;
|
|
||||||
var Parse = require('parse/node').Parse;
|
var Parse = require('parse/node').Parse;
|
||||||
|
|
||||||
var Schema = require('./Schema');
|
var Schema = require('./../Schema');
|
||||||
var transform = require('./transform');
|
var transform = require('./../transform');
|
||||||
|
|
||||||
// options can contain:
|
// options can contain:
|
||||||
// collectionPrefix: the string to put in front of every collection name.
|
// collectionPrefix: the string to put in front of every collection name.
|
||||||
function ExportAdapter(mongoURI, options = {}) {
|
function DatabaseController(adapter, { collectionPrefix } = {}) {
|
||||||
this.mongoURI = mongoURI;
|
this.adapter = adapter;
|
||||||
|
|
||||||
this.collectionPrefix = options.collectionPrefix;
|
this.collectionPrefix = collectionPrefix;
|
||||||
|
|
||||||
// We don't want a mutable this.schema, because then you could have
|
// We don't want a mutable this.schema, because then you could have
|
||||||
// one request that uses different schemas for different parts of
|
// one request that uses different schemas for different parts of
|
||||||
@@ -25,25 +24,13 @@ function ExportAdapter(mongoURI, options = {}) {
|
|||||||
|
|
||||||
// Connects to the database. Returns a promise that resolves when the
|
// Connects to the database. Returns a promise that resolves when the
|
||||||
// connection is successful.
|
// connection is successful.
|
||||||
// this.db will be populated with a Mongo "Db" object when the
|
DatabaseController.prototype.connect = function() {
|
||||||
// promise resolves successfully.
|
return this.adapter.connect();
|
||||||
ExportAdapter.prototype.connect = function() {
|
|
||||||
if (this.connectionPromise) {
|
|
||||||
// There's already a connection in progress.
|
|
||||||
return this.connectionPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.connectionPromise = Promise.resolve().then(() => {
|
|
||||||
return MongoClient.connect(this.mongoURI);
|
|
||||||
}).then((db) => {
|
|
||||||
this.db = db;
|
|
||||||
});
|
|
||||||
return this.connectionPromise;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns a promise for a Mongo collection.
|
// Returns a promise for a Mongo collection.
|
||||||
// Generally just for internal use.
|
// Generally just for internal use.
|
||||||
ExportAdapter.prototype.collection = function(className) {
|
DatabaseController.prototype.collection = function(className) {
|
||||||
if (!Schema.classNameIsValid(className)) {
|
if (!Schema.classNameIsValid(className)) {
|
||||||
throw new Parse.Error(Parse.Error.INVALID_CLASS_NAME,
|
throw new Parse.Error(Parse.Error.INVALID_CLASS_NAME,
|
||||||
'invalid className: ' + className);
|
'invalid className: ' + className);
|
||||||
@@ -51,10 +38,8 @@ ExportAdapter.prototype.collection = function(className) {
|
|||||||
return this.rawCollection(className);
|
return this.rawCollection(className);
|
||||||
};
|
};
|
||||||
|
|
||||||
ExportAdapter.prototype.rawCollection = function(className) {
|
DatabaseController.prototype.rawCollection = function(className) {
|
||||||
return this.connect().then(() => {
|
return this.adapter.collection(this.collectionPrefix + className);
|
||||||
return this.db.collection(this.collectionPrefix + className);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function returnsTrue() {
|
function returnsTrue() {
|
||||||
@@ -64,7 +49,7 @@ function returnsTrue() {
|
|||||||
// Returns a promise for a schema object.
|
// Returns a promise for a schema object.
|
||||||
// If we are provided a acceptor, then we run it on the schema.
|
// If we are provided a acceptor, then we run it on the schema.
|
||||||
// If the schema isn't accepted, we reload it at most once.
|
// If the schema isn't accepted, we reload it at most once.
|
||||||
ExportAdapter.prototype.loadSchema = function(acceptor = returnsTrue) {
|
DatabaseController.prototype.loadSchema = function(acceptor = returnsTrue) {
|
||||||
|
|
||||||
if (!this.schemaPromise) {
|
if (!this.schemaPromise) {
|
||||||
this.schemaPromise = this.collection('_SCHEMA').then((coll) => {
|
this.schemaPromise = this.collection('_SCHEMA').then((coll) => {
|
||||||
@@ -88,8 +73,8 @@ ExportAdapter.prototype.loadSchema = function(acceptor = returnsTrue) {
|
|||||||
|
|
||||||
// Returns a promise for the classname that is related to the given
|
// Returns a promise for the classname that is related to the given
|
||||||
// classname through the key.
|
// classname through the key.
|
||||||
// TODO: make this not in the ExportAdapter interface
|
// TODO: make this not in the DatabaseController interface
|
||||||
ExportAdapter.prototype.redirectClassNameForKey = function(className, key) {
|
DatabaseController.prototype.redirectClassNameForKey = function(className, key) {
|
||||||
return this.loadSchema().then((schema) => {
|
return this.loadSchema().then((schema) => {
|
||||||
var t = schema.getExpectedType(className, key);
|
var t = schema.getExpectedType(className, key);
|
||||||
var match = t.match(/^relation<(.*)>$/);
|
var match = t.match(/^relation<(.*)>$/);
|
||||||
@@ -105,7 +90,7 @@ ExportAdapter.prototype.redirectClassNameForKey = function(className, key) {
|
|||||||
// Returns a promise that resolves to the new schema.
|
// Returns a promise that resolves to the new schema.
|
||||||
// This does not update this.schema, because in a situation like a
|
// This does not update this.schema, because in a situation like a
|
||||||
// batch request, that could confuse other users of the schema.
|
// batch request, that could confuse other users of the schema.
|
||||||
ExportAdapter.prototype.validateObject = function(className, object, query) {
|
DatabaseController.prototype.validateObject = function(className, object, query) {
|
||||||
return this.loadSchema().then((schema) => {
|
return this.loadSchema().then((schema) => {
|
||||||
return schema.validateObject(className, object, query);
|
return schema.validateObject(className, object, query);
|
||||||
});
|
});
|
||||||
@@ -113,7 +98,7 @@ ExportAdapter.prototype.validateObject = function(className, object, query) {
|
|||||||
|
|
||||||
// Like transform.untransformObject but you need to provide a className.
|
// Like transform.untransformObject but you need to provide a className.
|
||||||
// Filters out any data that shouldn't be on this REST-formatted object.
|
// Filters out any data that shouldn't be on this REST-formatted object.
|
||||||
ExportAdapter.prototype.untransformObject = function(
|
DatabaseController.prototype.untransformObject = function(
|
||||||
schema, isMaster, aclGroup, className, mongoObject) {
|
schema, isMaster, aclGroup, className, mongoObject) {
|
||||||
var object = transform.untransformObject(schema, className, mongoObject);
|
var object = transform.untransformObject(schema, className, mongoObject);
|
||||||
|
|
||||||
@@ -138,7 +123,7 @@ ExportAdapter.prototype.untransformObject = function(
|
|||||||
// acl: a list of strings. If the object to be updated has an ACL,
|
// acl: a list of strings. If the object to be updated has an ACL,
|
||||||
// one of the provided strings must provide the caller with
|
// one of the provided strings must provide the caller with
|
||||||
// write permissions.
|
// write permissions.
|
||||||
ExportAdapter.prototype.update = function(className, query, update, options) {
|
DatabaseController.prototype.update = function(className, query, update, options) {
|
||||||
var acceptor = function(schema) {
|
var acceptor = function(schema) {
|
||||||
return schema.hasKeys(className, Object.keys(query));
|
return schema.hasKeys(className, Object.keys(query));
|
||||||
};
|
};
|
||||||
@@ -196,7 +181,7 @@ ExportAdapter.prototype.update = function(className, query, update, options) {
|
|||||||
// Returns a promise that resolves successfully when these are
|
// Returns a promise that resolves successfully when these are
|
||||||
// processed.
|
// processed.
|
||||||
// This mutates update.
|
// This mutates update.
|
||||||
ExportAdapter.prototype.handleRelationUpdates = function(className,
|
DatabaseController.prototype.handleRelationUpdates = function(className,
|
||||||
objectId,
|
objectId,
|
||||||
update) {
|
update) {
|
||||||
var pending = [];
|
var pending = [];
|
||||||
@@ -243,7 +228,7 @@ ExportAdapter.prototype.handleRelationUpdates = function(className,
|
|||||||
|
|
||||||
// Adds a relation.
|
// Adds a relation.
|
||||||
// Returns a promise that resolves successfully iff the add was successful.
|
// Returns a promise that resolves successfully iff the add was successful.
|
||||||
ExportAdapter.prototype.addRelation = function(key, fromClassName,
|
DatabaseController.prototype.addRelation = function(key, fromClassName,
|
||||||
fromId, toId) {
|
fromId, toId) {
|
||||||
var doc = {
|
var doc = {
|
||||||
relatedId: toId,
|
relatedId: toId,
|
||||||
@@ -258,7 +243,7 @@ ExportAdapter.prototype.addRelation = function(key, fromClassName,
|
|||||||
// Removes a relation.
|
// Removes a relation.
|
||||||
// Returns a promise that resolves successfully iff the remove was
|
// Returns a promise that resolves successfully iff the remove was
|
||||||
// successful.
|
// successful.
|
||||||
ExportAdapter.prototype.removeRelation = function(key, fromClassName,
|
DatabaseController.prototype.removeRelation = function(key, fromClassName,
|
||||||
fromId, toId) {
|
fromId, toId) {
|
||||||
var doc = {
|
var doc = {
|
||||||
relatedId: toId,
|
relatedId: toId,
|
||||||
@@ -277,7 +262,7 @@ ExportAdapter.prototype.removeRelation = function(key, fromClassName,
|
|||||||
// acl: a list of strings. If the object to be updated has an ACL,
|
// acl: a list of strings. If the object to be updated has an ACL,
|
||||||
// one of the provided strings must provide the caller with
|
// one of the provided strings must provide the caller with
|
||||||
// write permissions.
|
// write permissions.
|
||||||
ExportAdapter.prototype.destroy = function(className, query, options = {}) {
|
DatabaseController.prototype.destroy = function(className, query, options = {}) {
|
||||||
var isMaster = !('acl' in options);
|
var isMaster = !('acl' in options);
|
||||||
var aclGroup = options.acl || [];
|
var aclGroup = options.acl || [];
|
||||||
|
|
||||||
@@ -320,7 +305,7 @@ ExportAdapter.prototype.destroy = function(className, query, options = {}) {
|
|||||||
|
|
||||||
// Inserts an object into the database.
|
// Inserts an object into the database.
|
||||||
// Returns a promise that resolves successfully iff the object saved.
|
// Returns a promise that resolves successfully iff the object saved.
|
||||||
ExportAdapter.prototype.create = function(className, object, options) {
|
DatabaseController.prototype.create = function(className, object, options) {
|
||||||
var schema;
|
var schema;
|
||||||
var isMaster = !('acl' in options);
|
var isMaster = !('acl' in options);
|
||||||
var aclGroup = options.acl || [];
|
var aclGroup = options.acl || [];
|
||||||
@@ -346,7 +331,7 @@ ExportAdapter.prototype.create = function(className, object, options) {
|
|||||||
// This should only be used for testing - use 'find' for normal code
|
// This should only be used for testing - use 'find' for normal code
|
||||||
// to avoid Mongo-format dependencies.
|
// to avoid Mongo-format dependencies.
|
||||||
// Returns a promise that resolves to a list of items.
|
// Returns a promise that resolves to a list of items.
|
||||||
ExportAdapter.prototype.mongoFind = function(className, query, options = {}) {
|
DatabaseController.prototype.mongoFind = function(className, query, options = {}) {
|
||||||
return this.collection(className).then((coll) => {
|
return this.collection(className).then((coll) => {
|
||||||
return coll.find(query, options).toArray();
|
return coll.find(query, options).toArray();
|
||||||
});
|
});
|
||||||
@@ -355,19 +340,13 @@ ExportAdapter.prototype.mongoFind = function(className, query, options = {}) {
|
|||||||
// Deletes everything in the database matching the current collectionPrefix
|
// Deletes everything in the database matching the current collectionPrefix
|
||||||
// Won't delete collections in the system namespace
|
// Won't delete collections in the system namespace
|
||||||
// Returns a promise.
|
// Returns a promise.
|
||||||
ExportAdapter.prototype.deleteEverything = function() {
|
DatabaseController.prototype.deleteEverything = function() {
|
||||||
this.schemaPromise = null;
|
this.schemaPromise = null;
|
||||||
|
|
||||||
return this.connect().then(() => {
|
return this.adapter.collectionsContaining(this.collectionPrefix).then(collections => {
|
||||||
return this.db.collections();
|
let promises = collections.map(collection => {
|
||||||
}).then((colls) => {
|
return collection.drop();
|
||||||
var promises = [];
|
});
|
||||||
for (var coll of colls) {
|
|
||||||
if (!coll.namespace.match(/\.system\./) &&
|
|
||||||
coll.collectionName.indexOf(this.collectionPrefix) === 0) {
|
|
||||||
promises.push(coll.drop());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -390,7 +369,7 @@ function keysForQuery(query) {
|
|||||||
|
|
||||||
// Returns a promise for a list of related ids given an owning id.
|
// Returns a promise for a list of related ids given an owning id.
|
||||||
// className here is the owning className.
|
// className here is the owning className.
|
||||||
ExportAdapter.prototype.relatedIds = function(className, key, owningId) {
|
DatabaseController.prototype.relatedIds = function(className, key, owningId) {
|
||||||
var joinTable = '_Join:' + key + ':' + className;
|
var joinTable = '_Join:' + key + ':' + className;
|
||||||
return this.collection(joinTable).then((coll) => {
|
return this.collection(joinTable).then((coll) => {
|
||||||
return coll.find({owningId: owningId}).toArray();
|
return coll.find({owningId: owningId}).toArray();
|
||||||
@@ -401,7 +380,7 @@ ExportAdapter.prototype.relatedIds = function(className, key, owningId) {
|
|||||||
|
|
||||||
// Returns a promise for a list of owning ids given some related ids.
|
// Returns a promise for a list of owning ids given some related ids.
|
||||||
// className here is the owning className.
|
// className here is the owning className.
|
||||||
ExportAdapter.prototype.owningIds = function(className, key, relatedIds) {
|
DatabaseController.prototype.owningIds = function(className, key, relatedIds) {
|
||||||
var joinTable = '_Join:' + key + ':' + className;
|
var joinTable = '_Join:' + key + ':' + className;
|
||||||
return this.collection(joinTable).then((coll) => {
|
return this.collection(joinTable).then((coll) => {
|
||||||
return coll.find({relatedId: {'$in': relatedIds}}).toArray();
|
return coll.find({relatedId: {'$in': relatedIds}}).toArray();
|
||||||
@@ -414,7 +393,7 @@ ExportAdapter.prototype.owningIds = function(className, key, relatedIds) {
|
|||||||
// equal-to-pointer constraints on relation fields.
|
// equal-to-pointer constraints on relation fields.
|
||||||
// Returns a promise that resolves when query is mutated
|
// Returns a promise that resolves when query is mutated
|
||||||
// TODO: this only handles one of these at a time - make it handle more
|
// TODO: this only handles one of these at a time - make it handle more
|
||||||
ExportAdapter.prototype.reduceInRelation = function(className, query, schema) {
|
DatabaseController.prototype.reduceInRelation = function(className, query, schema) {
|
||||||
// Search for an in-relation or equal-to-relation
|
// Search for an in-relation or equal-to-relation
|
||||||
for (var key in query) {
|
for (var key in query) {
|
||||||
if (query[key] &&
|
if (query[key] &&
|
||||||
@@ -442,7 +421,7 @@ ExportAdapter.prototype.reduceInRelation = function(className, query, schema) {
|
|||||||
|
|
||||||
// Modifies query so that it no longer has $relatedTo
|
// Modifies query so that it no longer has $relatedTo
|
||||||
// Returns a promise that resolves when query is mutated
|
// Returns a promise that resolves when query is mutated
|
||||||
ExportAdapter.prototype.reduceRelationKeys = function(className, query) {
|
DatabaseController.prototype.reduceRelationKeys = function(className, query) {
|
||||||
var relatedTo = query['$relatedTo'];
|
var relatedTo = query['$relatedTo'];
|
||||||
if (relatedTo) {
|
if (relatedTo) {
|
||||||
return this.relatedIds(
|
return this.relatedIds(
|
||||||
@@ -461,7 +440,7 @@ ExportAdapter.prototype.reduceRelationKeys = function(className, query) {
|
|||||||
// none, then build the geoindex.
|
// none, then build the geoindex.
|
||||||
// This could be improved a lot but it's not clear if that's a good
|
// This could be improved a lot but it's not clear if that's a good
|
||||||
// idea. Or even if this behavior is a good idea.
|
// idea. Or even if this behavior is a good idea.
|
||||||
ExportAdapter.prototype.smartFind = function(coll, where, options) {
|
DatabaseController.prototype.smartFind = function(coll, where, options) {
|
||||||
return coll.find(where, options).toArray()
|
return coll.find(where, options).toArray()
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
return result;
|
return result;
|
||||||
@@ -502,7 +481,7 @@ ExportAdapter.prototype.smartFind = function(coll, where, options) {
|
|||||||
// TODO: make userIds not needed here. The db adapter shouldn't know
|
// TODO: make userIds not needed here. The db adapter shouldn't know
|
||||||
// anything about users, ideally. Then, improve the format of the ACL
|
// anything about users, ideally. Then, improve the format of the ACL
|
||||||
// arg to work like the others.
|
// arg to work like the others.
|
||||||
ExportAdapter.prototype.find = function(className, query, options = {}) {
|
DatabaseController.prototype.find = function(className, query, options = {}) {
|
||||||
var mongoOptions = {};
|
var mongoOptions = {};
|
||||||
if (options.skip) {
|
if (options.skip) {
|
||||||
mongoOptions.skip = options.skip;
|
mongoOptions.skip = options.skip;
|
||||||
@@ -568,4 +547,4 @@ ExportAdapter.prototype.find = function(className, query, options = {}) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = ExportAdapter;
|
module.exports = DatabaseController;
|
||||||
@@ -13,11 +13,12 @@
|
|||||||
// * destroy(className, query, options)
|
// * destroy(className, query, options)
|
||||||
// * This list is incomplete and the database process is not fully modularized.
|
// * This list is incomplete and the database process is not fully modularized.
|
||||||
//
|
//
|
||||||
// Default is ExportAdapter, which uses mongo.
|
// Default is MongoStorageAdapter.
|
||||||
|
|
||||||
var ExportAdapter = require('./ExportAdapter');
|
import DatabaseController from './Controllers/DatabaseController';
|
||||||
|
import MongoStorageAdapter from './Adapters/Storage/Mongo/MongoStorageAdapter';
|
||||||
|
|
||||||
var adapter = ExportAdapter;
|
let adapter = MongoStorageAdapter;
|
||||||
var dbConnections = {};
|
var dbConnections = {};
|
||||||
var databaseURI = 'mongodb://localhost:27017/parse';
|
var databaseURI = 'mongodb://localhost:27017/parse';
|
||||||
var appDatabaseURIs = {};
|
var appDatabaseURIs = {};
|
||||||
@@ -46,10 +47,11 @@ function getDatabaseConnection(appId: string, collectionPrefix: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var dbURI = (appDatabaseURIs[appId] ? appDatabaseURIs[appId] : databaseURI);
|
var dbURI = (appDatabaseURIs[appId] ? appDatabaseURIs[appId] : databaseURI);
|
||||||
dbConnections[appId] = new adapter(dbURI, {
|
|
||||||
|
let storageAdapter = new adapter(dbURI);
|
||||||
|
dbConnections[appId] = new DatabaseController(storageAdapter, {
|
||||||
collectionPrefix: collectionPrefix
|
collectionPrefix: collectionPrefix
|
||||||
});
|
});
|
||||||
dbConnections[appId].connect();
|
|
||||||
return dbConnections[appId];
|
return dbConnections[appId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ function modifySchema(req) {
|
|||||||
.then(() => schema.deleteField(
|
.then(() => schema.deleteField(
|
||||||
submittedFieldName,
|
submittedFieldName,
|
||||||
className,
|
className,
|
||||||
req.config.database.db,
|
req.config.database.adapter.database,
|
||||||
req.config.database.collectionPrefix
|
req.config.database.collectionPrefix
|
||||||
));
|
));
|
||||||
deletionPromises.push(promise);
|
deletionPromises.push(promise);
|
||||||
@@ -246,7 +246,7 @@ function deleteSchema(req) {
|
|||||||
//tried to delete non-existant class
|
//tried to delete non-existant class
|
||||||
resolve({ response: {}});
|
resolve({ response: {}});
|
||||||
} else {
|
} else {
|
||||||
removeJoinTables(req.config.database.db, req.config.database.collectionPrefix, doc.value)
|
removeJoinTables(req.config.database.adapter.database, req.config.database.collectionPrefix, doc.value)
|
||||||
.then(resolve, reject);
|
.then(resolve, reject);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
// keeping it this way for now.
|
// keeping it this way for now.
|
||||||
//
|
//
|
||||||
// In API-handling code, you should only use the Schema class via the
|
// In API-handling code, you should only use the Schema class via the
|
||||||
// ExportAdapter. This will let us replace the schema logic for
|
// DatabaseController. This will let us replace the schema logic for
|
||||||
// different databases.
|
// different databases.
|
||||||
// TODO: hide all schema logic inside the database adapter.
|
// TODO: hide all schema logic inside the database adapter.
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ addParseCloud();
|
|||||||
|
|
||||||
// ParseServer works like a constructor of an express app.
|
// ParseServer works like a constructor of an express app.
|
||||||
// The args that we understand are:
|
// The args that we understand are:
|
||||||
// "databaseAdapter": a class like ExportAdapter providing create, find,
|
// "databaseAdapter": a class like DatabaseController providing create, find,
|
||||||
// update, and delete
|
// update, and delete
|
||||||
// "filesAdapter": a class like GridStoreAdapter providing create, get,
|
// "filesAdapter": a class like GridStoreAdapter providing create, get,
|
||||||
// and delete
|
// and delete
|
||||||
|
|||||||
Reference in New Issue
Block a user