* Move ACL transforming into Parse Server For the database adapters, it will be more performant and easier to work with _rperm and _wperm than with the ACL object. This way we can type it as an array and so on, and once we have stronger validations in Parse Server, we can type it as an array containing strings of length < x, which will be much much better in sql databases. * Use destructuring
264 lines
8.4 KiB
JavaScript
264 lines
8.4 KiB
JavaScript
// These tests are unit tests designed to only test transform.js.
|
||
"use strict";
|
||
|
||
let transform = require('../src/Adapters/Storage/Mongo/MongoTransform');
|
||
let dd = require('deep-diff');
|
||
let mongodb = require('mongodb');
|
||
|
||
describe('parseObjectToMongoObjectForCreate', () => {
|
||
|
||
it('a basic number', (done) => {
|
||
var input = {five: 5};
|
||
var output = transform.parseObjectToMongoObjectForCreate(null, input, {
|
||
fields: {five: {type: 'Number'}}
|
||
});
|
||
jequal(input, output);
|
||
done();
|
||
});
|
||
|
||
it('an object with null values', (done) => {
|
||
var input = {objectWithNullValues: {isNull: null, notNull: 3}};
|
||
var output = transform.parseObjectToMongoObjectForCreate(null, input, {
|
||
fields: {objectWithNullValues: {type: 'object'}}
|
||
});
|
||
jequal(input, output);
|
||
done();
|
||
});
|
||
|
||
it('built-in timestamps', (done) => {
|
||
var input = {
|
||
createdAt: "2015-10-06T21:24:50.332Z",
|
||
updatedAt: "2015-10-06T21:24:50.332Z"
|
||
};
|
||
var output = transform.parseObjectToMongoObjectForCreate(null, input, { fields: {} });
|
||
expect(output._created_at instanceof Date).toBe(true);
|
||
expect(output._updated_at instanceof Date).toBe(true);
|
||
done();
|
||
});
|
||
|
||
it('array of pointers', (done) => {
|
||
var pointer = {
|
||
__type: 'Pointer',
|
||
objectId: 'myId',
|
||
className: 'Blah',
|
||
};
|
||
var out = transform.parseObjectToMongoObjectForCreate(null, {pointers: [pointer]},{
|
||
fields: {pointers: {type: 'Array'}}
|
||
});
|
||
jequal([pointer], out.pointers);
|
||
done();
|
||
});
|
||
|
||
//TODO: object creation requests shouldn't be seeing __op delete, it makes no sense to
|
||
//have __op delete in a new object. Figure out what this should actually be testing.
|
||
notWorking('a delete op', (done) => {
|
||
var input = {deleteMe: {__op: 'Delete'}};
|
||
var output = transform.parseObjectToMongoObjectForCreate(null, input, { fields: {} });
|
||
jequal(output, {});
|
||
done();
|
||
});
|
||
|
||
it('Doesnt allow ACL, as Parse Server should tranform ACL to _wperm + _rperm', done => {
|
||
var input = {ACL: {'0123': {'read': true, 'write': true}}};
|
||
expect(() => transform.parseObjectToMongoObjectForCreate(null, input, { fields: {} })).toThrow();
|
||
done();
|
||
});
|
||
|
||
describe('GeoPoints', () => {
|
||
it('plain', (done) => {
|
||
var geoPoint = {__type: 'GeoPoint', longitude: 180, latitude: -180};
|
||
var out = transform.parseObjectToMongoObjectForCreate(null, {location: geoPoint},{
|
||
fields: {location: {type: 'GeoPoint'}}
|
||
});
|
||
expect(out.location).toEqual([180, -180]);
|
||
done();
|
||
});
|
||
|
||
it('in array', (done) => {
|
||
var geoPoint = {__type: 'GeoPoint', longitude: 180, latitude: -180};
|
||
var out = transform.parseObjectToMongoObjectForCreate(null, {locations: [geoPoint, geoPoint]},{
|
||
fields: {locations: {type: 'Array'}}
|
||
});
|
||
expect(out.locations).toEqual([geoPoint, geoPoint]);
|
||
done();
|
||
});
|
||
|
||
it('in sub-object', (done) => {
|
||
var geoPoint = {__type: 'GeoPoint', longitude: 180, latitude: -180};
|
||
var out = transform.parseObjectToMongoObjectForCreate(null, { locations: { start: geoPoint }},{
|
||
fields: {locations: {type: 'Object'}}
|
||
});
|
||
expect(out).toEqual({ locations: { start: geoPoint } });
|
||
done();
|
||
});
|
||
});
|
||
});
|
||
|
||
describe('transformWhere', () => {
|
||
it('objectId', (done) => {
|
||
var out = transform.transformWhere(null, {objectId: 'foo'});
|
||
expect(out._id).toEqual('foo');
|
||
done();
|
||
});
|
||
|
||
it('objectId in a list', (done) => {
|
||
var input = {
|
||
objectId: {'$in': ['one', 'two', 'three']},
|
||
};
|
||
var output = transform.transformWhere(null, input);
|
||
jequal(input.objectId, output._id);
|
||
done();
|
||
});
|
||
});
|
||
|
||
describe('mongoObjectToParseObject', () => {
|
||
it('built-in timestamps', (done) => {
|
||
var input = {createdAt: new Date(), updatedAt: new Date()};
|
||
var output = transform.mongoObjectToParseObject(null, input, { fields: {} });
|
||
expect(typeof output.createdAt).toEqual('string');
|
||
expect(typeof output.updatedAt).toEqual('string');
|
||
done();
|
||
});
|
||
|
||
it('pointer', (done) => {
|
||
var input = {_p_userPointer: '_User$123'};
|
||
var output = transform.mongoObjectToParseObject(null, input, {
|
||
fields: { userPointer: { type: 'Pointer', targetClass: '_User' } },
|
||
});
|
||
expect(typeof output.userPointer).toEqual('object');
|
||
expect(output.userPointer).toEqual(
|
||
{__type: 'Pointer', className: '_User', objectId: '123'}
|
||
);
|
||
done();
|
||
});
|
||
|
||
it('null pointer', (done) => {
|
||
var input = {_p_userPointer: null};
|
||
var output = transform.mongoObjectToParseObject(null, input, {
|
||
fields: { userPointer: { type: 'Pointer', targetClass: '_User' } },
|
||
});
|
||
expect(output.userPointer).toBeUndefined();
|
||
done();
|
||
});
|
||
|
||
it('file', (done) => {
|
||
var input = {picture: 'pic.jpg'};
|
||
var output = transform.mongoObjectToParseObject(null, input, {
|
||
fields: { picture: { type: 'File' }},
|
||
});
|
||
expect(typeof output.picture).toEqual('object');
|
||
expect(output.picture).toEqual({__type: 'File', name: 'pic.jpg'});
|
||
done();
|
||
});
|
||
|
||
it('geopoint', (done) => {
|
||
var input = {location: [180, -180]};
|
||
var output = transform.mongoObjectToParseObject(null, input, {
|
||
fields: { location: { type: 'GeoPoint' }},
|
||
});
|
||
expect(typeof output.location).toEqual('object');
|
||
expect(output.location).toEqual(
|
||
{__type: 'GeoPoint', longitude: 180, latitude: -180}
|
||
);
|
||
done();
|
||
});
|
||
|
||
it('nested array', (done) => {
|
||
var input = {arr: [{_testKey: 'testValue' }]};
|
||
var output = transform.mongoObjectToParseObject(null, input, {
|
||
fields: { arr: { type: 'Array' } },
|
||
});
|
||
expect(Array.isArray(output.arr)).toEqual(true);
|
||
expect(output.arr).toEqual([{ _testKey: 'testValue'}]);
|
||
done();
|
||
});
|
||
|
||
it('untransforms objects containing nested special keys', done => {
|
||
let input = {array: [{
|
||
_id: "Test ID",
|
||
_hashed_password: "I Don't know why you would name a key this, but if you do it should work",
|
||
_tombstone: {
|
||
_updated_at: "I'm sure people will nest keys like this",
|
||
_acl: 7,
|
||
_id: { someString: "str", someNumber: 7},
|
||
regularKey: { moreContents: [1, 2, 3] },
|
||
},
|
||
regularKey: "some data",
|
||
}]}
|
||
let output = transform.mongoObjectToParseObject(null, input, {
|
||
fields: { array: { type: 'Array' }},
|
||
});
|
||
expect(dd(output, input)).toEqual(undefined);
|
||
done();
|
||
});
|
||
});
|
||
|
||
describe('transform schema key changes', () => {
|
||
|
||
it('changes new pointer key', (done) => {
|
||
var input = {
|
||
somePointer: {__type: 'Pointer', className: 'Micro', objectId: 'oft'}
|
||
};
|
||
var output = transform.parseObjectToMongoObjectForCreate(null, input, {
|
||
fields: {somePointer: {type: 'Pointer'}}
|
||
});
|
||
expect(typeof output._p_somePointer).toEqual('string');
|
||
expect(output._p_somePointer).toEqual('Micro$oft');
|
||
done();
|
||
});
|
||
|
||
it('changes existing pointer keys', (done) => {
|
||
var input = {
|
||
userPointer: {__type: 'Pointer', className: '_User', objectId: 'qwerty'}
|
||
};
|
||
var output = transform.parseObjectToMongoObjectForCreate(null, input, {
|
||
fields: {userPointer: {type: 'Pointer'}}
|
||
});
|
||
expect(typeof output._p_userPointer).toEqual('string');
|
||
expect(output._p_userPointer).toEqual('_User$qwerty');
|
||
done();
|
||
});
|
||
|
||
it('writes the old ACL format in addition to rperm and wperm', (done) => {
|
||
var input = {
|
||
_rperm: ['*'],
|
||
_wperm: ['Kevin'],
|
||
};
|
||
|
||
var output = transform.parseObjectToMongoObjectForCreate(null, input, { fields: {} });
|
||
expect(typeof output._acl).toEqual('object');
|
||
expect(output._acl["Kevin"].w).toBeTruthy();
|
||
expect(output._acl["Kevin"].r).toBeUndefined();
|
||
done();
|
||
})
|
||
|
||
it('untransforms from _rperm and _wperm to ACL', (done) => {
|
||
var input = {
|
||
_rperm: ["*"],
|
||
_wperm: ["Kevin"]
|
||
};
|
||
var output = transform.mongoObjectToParseObject(null, input, { fields: {} });
|
||
expect(output._rperm).toEqual(['*']);
|
||
expect(output._wperm).toEqual(['Kevin']);
|
||
expect(output.ACL).toBeUndefined()
|
||
done();
|
||
});
|
||
|
||
it('untransforms mongodb number types', (done) => {
|
||
var input = {
|
||
long: mongodb.Long.fromNumber(Number.MAX_SAFE_INTEGER),
|
||
double: new mongodb.Double(Number.MAX_VALUE)
|
||
}
|
||
var output = transform.mongoObjectToParseObject(null, input, {
|
||
fields: {
|
||
long: { type: 'Number' },
|
||
double: { type: 'Number' },
|
||
},
|
||
});
|
||
expect(output.long).toBe(Number.MAX_SAFE_INTEGER);
|
||
expect(output.double).toBe(Number.MAX_VALUE);
|
||
done();
|
||
});
|
||
|
||
});
|