diff --git a/.travis.yml b/.travis.yml index b1fd440681e..6c79fd16cf7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ env: branches: only: - master + - /^[0-9].[0-9].[0-9](-.*)?$/ cache: directories: - "$HOME/.mongodb/versions/downloads" diff --git a/spec/ParseAPI.spec.js b/spec/ParseAPI.spec.js index a5eeffbfc1f..09336a556e5 100644 --- a/spec/ParseAPI.spec.js +++ b/spec/ParseAPI.spec.js @@ -1271,4 +1271,33 @@ describe('miscellaneous', function() { }); }); + it('gets relation fields', (done) => { + let object = new Parse.Object('AnObject'); + let relatedObject = new Parse.Object('RelatedObject'); + Parse.Object.saveAll([object, relatedObject]).then(() => { + object.relation('related').add(relatedObject); + return object.save(); + }).then(() => { + let headers = { + 'Content-Type': 'application/json', + 'X-Parse-Application-Id': 'test', + 'X-Parse-REST-API-Key': 'rest' + }; + let requestOptions = { + headers: headers, + url: 'http://localhost:8378/1/classes/AnObject', + json: true + }; + request.get(requestOptions, (err, res, body) => { + expect(body.results.length).toBe(1); + let result = body.results[0]; + expect(result.related).toEqual({ + __type: "Relation", + className: 'RelatedObject' + }) + done(); + }); + }) + }) + }); diff --git a/spec/helper.js b/spec/helper.js index c134f339ab0..03ddff97435 100644 --- a/spec/helper.js +++ b/spec/helper.js @@ -8,6 +8,7 @@ var express = require('express'); var facebook = require('../src/authDataManager/facebook'); var ParseServer = require('../src/index').ParseServer; var path = require('path'); +var TestUtils = require('../src/index').TestUtils; var databaseURI = process.env.DATABASE_URI; var cloudMain = process.env.CLOUD_CODE_MAIN || './spec/cloud/main.js'; @@ -88,7 +89,7 @@ beforeEach(function(done) { afterEach(function(done) { Parse.User.logOut().then(() => { - return clearData(); + return TestUtils.destroyAllDataPermanently(); }).then(() => { done(); }, (error) => { @@ -232,14 +233,6 @@ function mockFacebook() { return facebook; } -function clearData() { - var promises = []; - for (var conn in DatabaseAdapter.dbConnections) { - promises.push(DatabaseAdapter.dbConnections[conn].deleteEverything()); - } - return Promise.all(promises); -} - // This is polluting, but, it makes it way easier to directly port old tests. global.Parse = Parse; global.TestObject = TestObject; diff --git a/spec/transform.spec.js b/spec/transform.spec.js index 896df51fe29..4a47f3598fe 100644 --- a/spec/transform.spec.js +++ b/spec/transform.spec.js @@ -13,6 +13,9 @@ var dummySchema = { return 'geopoint'; } return; + }, + getRelationFields: function() { + return {} } }; diff --git a/src/DatabaseAdapter.js b/src/DatabaseAdapter.js index 51403ba3cf1..3afdf1364ef 100644 --- a/src/DatabaseAdapter.js +++ b/src/DatabaseAdapter.js @@ -49,6 +49,18 @@ function clearDatabaseSettings() { appDatabaseOptions = {}; } +//Used by tests +function destroyAllDataPermanently() { + if (process.env.TESTING) { + var promises = []; + for (var conn in dbConnections) { + promises.push(dbConnections[conn].deleteEverything()); + } + return Promise.all(promises); + } + throw 'Only supported in test environment'; +} + function getDatabaseConnection(appId: string, collectionPrefix: string) { if (dbConnections[appId]) { return dbConnections[appId]; @@ -71,5 +83,6 @@ module.exports = { setAppDatabaseOptions: setAppDatabaseOptions, setAppDatabaseURI: setAppDatabaseURI, clearDatabaseSettings: clearDatabaseSettings, + destroyAllDataPermanently: destroyAllDataPermanently, defaultDatabaseURI: databaseURI }; diff --git a/src/Schema.js b/src/Schema.js index 17970aa915a..7493d6a3740 100644 --- a/src/Schema.js +++ b/src/Schema.js @@ -636,6 +636,24 @@ class Schema { } return false; }; + + getRelationFields(className) { + if (this.data && this.data[className]) { + let classData = this.data[className]; + return Object.keys(classData).filter((field) => { + return classData[field].startsWith('relation'); + }).reduce((memo, field) => { + let type = classData[field]; + let className = type.slice('relation<'.length, type.length - 1); + memo[field] = { + __type: 'Relation', + className: className + }; + return memo; + }, {}); + } + return {}; + } } // Returns a promise for a new Schema. diff --git a/src/TestUtils.js b/src/TestUtils.js new file mode 100644 index 00000000000..ebdb9f99143 --- /dev/null +++ b/src/TestUtils.js @@ -0,0 +1,15 @@ +import { destroyAllDataPermanently } from './DatabaseAdapter'; + +let unsupported = function() { + throw 'Only supported in test environment'; +}; + +let _destroyAllDataPermanently; +if (process.env.TESTING) { + _destroyAllDataPermanently = destroyAllDataPermanently; +} else { + _destroyAllDataPermanently = unsupported; +} + +export default { + destroyAllDataPermanently: _destroyAllDataPermanently}; diff --git a/src/index.js b/src/index.js index 7c453454680..39075d50e1c 100644 --- a/src/index.js +++ b/src/index.js @@ -2,6 +2,7 @@ import winston from 'winston'; import ParseServer from './ParseServer'; import S3Adapter from 'parse-server-s3-adapter' import FileSystemAdapter from 'parse-server-fs-adapter' +import TestUtils from './TestUtils'; import { useExternal } from './deprecated' // Factory function @@ -15,4 +16,4 @@ _ParseServer.createLiveQueryServer = ParseServer.createLiveQueryServer; let GCSAdapter = useExternal('GCSAdapter', 'parse-server-gcs-adapter'); export default ParseServer; -export { S3Adapter, GCSAdapter, FileSystemAdapter, _ParseServer as ParseServer }; +export { S3Adapter, GCSAdapter, FileSystemAdapter, TestUtils, _ParseServer as ParseServer }; diff --git a/src/transform.js b/src/transform.js index 51627af45fc..eba2ea16b50 100644 --- a/src/transform.js +++ b/src/transform.js @@ -732,6 +732,11 @@ function untransformObject(schema, className, mongoObject, isNestedObject = fals mongoObject[key], true); } } + + if (!isNestedObject) { + let relationFields = schema.getRelationFields(className); + Object.assign(restObject, relationFields); + } return restObject; default: throw 'unknown js type';