Skip to content

Commit 2907315

Browse files
committed
wip: testing
1 parent 6cf6355 commit 2907315

File tree

7 files changed

+164
-81
lines changed

7 files changed

+164
-81
lines changed

spec/DefinedSchemas.spec.js

Lines changed: 83 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,6 @@
1-
// eslint-disable-next-line no-unused-vars
21
const { DefinedSchemas } = require('../lib/DefinedSchemas');
32
const Config = require('../lib/Config');
43

5-
// eslint-disable-next-line no-unused-vars
6-
const Toto = {
7-
className: 'Toto',
8-
fields: {
9-
objectId: { type: 'String' },
10-
createdAt: {
11-
type: 'Date',
12-
},
13-
updatedAt: {
14-
type: 'Date',
15-
},
16-
ACL: { type: 'ACL' },
17-
string: { type: 'String' },
18-
number: { type: 'Number' },
19-
pointer: { type: 'Pointer', targetClass: 'Pointer' },
20-
relation: { type: 'Relation', targetClass: 'Relation' },
21-
email: { type: 'String' },
22-
},
23-
indexes: {
24-
objectId: { objectId: 1 },
25-
string: { string: 1 },
26-
complex: { string: 1, number: 1 },
27-
},
28-
classLevelPermissions: {
29-
addField: {},
30-
create: { '*': true, 'role:ARole': false },
31-
},
32-
};
33-
344
fdescribe('DefinedSchemas', () => {
355
beforeEach(async () => {
366
const config = Config.get('test');
@@ -45,38 +15,41 @@ fdescribe('DefinedSchemas', () => {
4515
// await server.config.databaseController.schemaCache.clear();
4616
let schema = await new Parse.Schema('Test').get();
4717
const expectedFields = {
48-
className: 'Test',
49-
fields: {
50-
objectId: { type: 'String' },
51-
createdAt: { type: 'Date' },
52-
updatedAt: { type: 'Date' },
53-
ACL: { type: 'ACL' },
54-
},
55-
classLevelPermissions: {
56-
find: {},
57-
count: {},
58-
get: {},
59-
create: {},
60-
update: {},
61-
delete: {},
62-
addField: {},
63-
protectedFields: {},
64-
},
18+
objectId: { type: 'String' },
19+
createdAt: { type: 'Date' },
20+
updatedAt: { type: 'Date' },
21+
ACL: { type: 'ACL' },
6522
};
6623
expect(schema.fields).toEqual(expectedFields);
6724

6825
await server.config.databaseController.schemaCache.clear();
6926
// Will perform update
7027
await new DefinedSchemas([{ className: 'Test' }], server.config).execute();
7128
schema = await new Parse.Schema('Test').get();
72-
// indexes seems to be created in background so there was not found
73-
// on the first request
7429
expect(schema.fields).toEqual(expectedFields);
7530
});
76-
it('should not change default fields', async () => {
31+
it('should protect default fields', async () => {
7732
const server = await reconfigureServer();
7833

7934
const schemas = [
35+
{
36+
className: '_User',
37+
fields: {
38+
email: 'Object',
39+
},
40+
},
41+
{
42+
className: '_Role',
43+
fields: {
44+
users: 'Object',
45+
},
46+
},
47+
{
48+
className: '_Installation',
49+
fields: {
50+
installationId: 'Object',
51+
},
52+
},
8053
{
8154
className: 'Test',
8255
fields: {
@@ -95,16 +68,76 @@ fdescribe('DefinedSchemas', () => {
9568
ACL: { type: 'ACL' },
9669
};
9770

71+
const expectedUserFields = {
72+
objectId: { type: 'String' },
73+
createdAt: { type: 'Date' },
74+
updatedAt: { type: 'Date' },
75+
ACL: { type: 'ACL' },
76+
username: { type: 'String' },
77+
password: { type: 'String' },
78+
email: { type: 'String' },
79+
emailVerified: { type: 'Boolean' },
80+
authData: { type: 'Object' },
81+
};
82+
83+
const expectedRoleFields = {
84+
objectId: { type: 'String' },
85+
createdAt: { type: 'Date' },
86+
updatedAt: { type: 'Date' },
87+
ACL: { type: 'ACL' },
88+
name: { type: 'String' },
89+
users: { type: 'Relation', targetClass: '_User' },
90+
roles: { type: 'Relation', targetClass: '_Role' },
91+
};
92+
93+
const expectedInstallationFields = {
94+
objectId: { type: 'String' },
95+
createdAt: { type: 'Date' },
96+
updatedAt: { type: 'Date' },
97+
ACL: { type: 'ACL' },
98+
installationId: { type: 'String' },
99+
deviceToken: { type: 'String' },
100+
channels: { type: 'Array' },
101+
deviceType: { type: 'String' },
102+
pushType: { type: 'String' },
103+
GCMSenderId: { type: 'String' },
104+
timeZone: { type: 'String' },
105+
localeIdentifier: { type: 'String' },
106+
badge: { type: 'Number' },
107+
appVersion: { type: 'String' },
108+
appName: { type: 'String' },
109+
appIdentifier: { type: 'String' },
110+
parseVersion: { type: 'String' },
111+
};
112+
98113
// Perform create
99114
await new DefinedSchemas(schemas, server.config).execute();
100115
let schema = await new Parse.Schema('Test').get();
101116
expect(schema.fields).toEqual(expectedFields);
102117

118+
let userSchema = await new Parse.Schema('_User').get();
119+
expect(userSchema.fields).toEqual(expectedUserFields);
120+
121+
let roleSchema = await new Parse.Schema('_Role').get();
122+
expect(roleSchema.fields).toEqual(expectedRoleFields);
123+
124+
let installationSchema = await new Parse.Schema('_Installation').get();
125+
expect(installationSchema.fields).toEqual(expectedInstallationFields);
126+
103127
await server.config.databaseController.schemaCache.clear();
104128
// Perform update
105129
await new DefinedSchemas(schemas, server.config).execute();
106130
schema = await new Parse.Schema('Test').get();
107131
expect(schema.fields).toEqual(expectedFields);
132+
133+
userSchema = await new Parse.Schema('_User').get();
134+
expect(userSchema.fields).toEqual(expectedUserFields);
135+
136+
roleSchema = await new Parse.Schema('_Role').get();
137+
expect(roleSchema.fields).toEqual(expectedRoleFields);
138+
139+
installationSchema = await new Parse.Schema('_Installation').get();
140+
expect(installationSchema.fields).toEqual(expectedInstallationFields);
108141
});
109142
it('should create new fields', async () => {
110143
const server = await reconfigureServer();
@@ -217,12 +250,6 @@ fdescribe('DefinedSchemas', () => {
217250
await object.fetch({ useMasterKey: true });
218251
expect(object.get('aField')).toEqual('Hello');
219252
});
220-
describe('User', () => {
221-
xit('should protect default fields');
222-
});
223-
describe('Role', () => {
224-
xit('should protect default fields');
225-
});
226253
});
227254

228255
describe('Indexes', () => {

src/Adapters/Storage/Mongo/MongoSchemaCollection.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ class MongoSchemaCollection {
212212
.then(
213213
schema => {
214214
// If a field with this name already exists, it will be handled elsewhere.
215-
if (schema.fields[fieldName] != undefined) {
215+
if (schema.fields[fieldName] !== undefined) {
216216
return;
217217
}
218218
// The schema exists. Check for existing GeoPoints.
@@ -274,6 +274,20 @@ class MongoSchemaCollection {
274274
}
275275
});
276276
}
277+
278+
async updateFieldOptions(className: string, fieldName: string, fieldType: string) {
279+
// eslint-disable-next-line no-unused-vars
280+
const { type, targetClass, ...fieldOptions } = fieldType;
281+
await this.upsertSchema(
282+
className,
283+
{ [fieldName]: { $exists: true } },
284+
{
285+
$set: {
286+
[`_metadata.fields_options.${fieldName}`]: fieldOptions,
287+
},
288+
}
289+
);
290+
}
277291
}
278292

279293
// Exported for testing reasons and because we haven't moved all mongo schema format

src/Adapters/Storage/Mongo/MongoStorageAdapter.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,11 @@ export class MongoStorageAdapter implements StorageAdapter {
329329
.catch(err => this.handleError(err));
330330
}
331331

332+
async updateFieldOptions(className: string, fieldName: string, type: any) {
333+
const schemaCollection = await this._schemaCollection();
334+
await schemaCollection.updateFieldOptions(className, fieldName, type);
335+
}
336+
332337
addFieldIfNotExists(className: string, fieldName: string, type: any): Promise<void> {
333338
return this._schemaCollection()
334339
.then(schemaCollection => schemaCollection.addFieldIfNotExists(className, fieldName, type))

src/Adapters/Storage/Postgres/PostgresStorageAdapter.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,6 +1081,16 @@ export class PostgresStorageAdapter implements StorageAdapter {
10811081
});
10821082
}
10831083

1084+
async updateFieldOptions(className: string, fieldName: string, type: any) {
1085+
await this._client.tx('update-schema-field-options', async t => {
1086+
const path = `{fields,${fieldName}}`;
1087+
await t.none(
1088+
'UPDATE "_SCHEMA" SET "schema"=jsonb_set("schema", $<path>, $<type>) WHERE "className"=$<className>',
1089+
{ path, type, className }
1090+
);
1091+
});
1092+
}
1093+
10841094
// Drops a collection. Resolves with true if it was a Parse Schema (eg. _User, Custom, etc.)
10851095
// and resolves with false if it wasn't (eg. a join table). Rejects if deletion was impossible.
10861096
async deleteClass(className: string) {

src/Adapters/Storage/StorageAdapter.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export interface StorageAdapter {
3535
setClassLevelPermissions(className: string, clps: any): Promise<void>;
3636
createClass(className: string, schema: SchemaType): Promise<void>;
3737
addFieldIfNotExists(className: string, fieldName: string, type: any): Promise<void>;
38+
updateFieldOptions(className: string, fieldName: string, type: any): Promise<void>;
3839
deleteClass(className: string): Promise<void>;
3940
deleteAllClasses(fast: boolean): Promise<void>;
4041
deleteFields(className: string, schema: SchemaType, fieldNames: Array<string>): Promise<void>;

src/Controllers/SchemaController.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
// TODO: hide all schema logic inside the database adapter.
1717
// @flow-disable-next
1818
const Parse = require('parse/node').Parse;
19+
import _ from 'lodash';
1920
import { StorageAdapter } from '../Adapters/Storage/StorageAdapter';
2021
import DatabaseController from './DatabaseController';
2122
import Config from '../Config';
@@ -1110,7 +1111,15 @@ export default class SchemaController {
11101111
)} but got ${typeToString(type)}`
11111112
);
11121113
}
1113-
return undefined;
1114+
// If type options do not change
1115+
// we can safely return
1116+
if (_.isEqual(expectedType, type)) {
1117+
return undefined;
1118+
} else {
1119+
// Field options are may be changed
1120+
// ensure to have an update to date schema field
1121+
return this._dbAdapter.updateFieldOptions(className, fieldName, type);
1122+
}
11141123
}
11151124

11161125
return this._dbAdapter

0 commit comments

Comments
 (0)