Reduces number of calls to injectDefaultSchema (#5107)
This commit is contained in:
@@ -1032,9 +1032,12 @@ describe('SchemaController', () => {
|
||||
createdAt: { type: 'Date' },
|
||||
ACL: { type: 'ACL' },
|
||||
};
|
||||
expect(dd(schema.data.NewClass, expectedSchema)).toEqual(undefined);
|
||||
done();
|
||||
});
|
||||
expect(dd(schema.schemaData.NewClass.fields, expectedSchema)).toEqual(
|
||||
undefined
|
||||
);
|
||||
})
|
||||
.then(done)
|
||||
.catch(done.fail);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1268,14 +1271,15 @@ describe('SchemaController', () => {
|
||||
})
|
||||
.then(userSchema => {
|
||||
validateSchemaStructure(userSchema);
|
||||
validateSchemaDataStructure(schema.data);
|
||||
validateSchemaDataStructure(schema.schemaData);
|
||||
return schema.getOneSchema('_PushStatus', true);
|
||||
})
|
||||
.then(pushStatusSchema => {
|
||||
validateSchemaStructure(pushStatusSchema);
|
||||
validateSchemaDataStructure(schema.data);
|
||||
done();
|
||||
});
|
||||
validateSchemaDataStructure(schema.schemaData);
|
||||
})
|
||||
.then(done)
|
||||
.catch(done.fail);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -848,12 +848,12 @@ class DatabaseController {
|
||||
object: any,
|
||||
aclGroup: string[]
|
||||
): Promise<void> {
|
||||
const classSchema = schema.data[className];
|
||||
const classSchema = schema.schemaData[className];
|
||||
if (!classSchema) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
const fields = Object.keys(object);
|
||||
const schemaFields = Object.keys(classSchema);
|
||||
const schemaFields = Object.keys(classSchema.fields);
|
||||
const newKeys = fields.filter(field => {
|
||||
// Skip fields that are unset
|
||||
if (
|
||||
@@ -1346,7 +1346,7 @@ class DatabaseController {
|
||||
if (schema.testBaseCLP(className, aclGroup, operation)) {
|
||||
return query;
|
||||
}
|
||||
const perms = schema.perms[className];
|
||||
const perms = schema.schemaData[className].classLevelPermissions;
|
||||
const field =
|
||||
['get', 'find'].indexOf(operation) > -1
|
||||
? 'readUserFields'
|
||||
|
||||
@@ -381,6 +381,48 @@ const convertAdapterSchemaToParseSchema = ({ ...schema }) => {
|
||||
return schema;
|
||||
};
|
||||
|
||||
class SchemaData {
|
||||
__data: any;
|
||||
constructor(allSchemas = []) {
|
||||
this.__data = {};
|
||||
allSchemas.forEach(schema => {
|
||||
Object.defineProperty(this, schema.className, {
|
||||
get: () => {
|
||||
if (!this.__data[schema.className]) {
|
||||
const data = {};
|
||||
data.fields = injectDefaultSchema(schema).fields;
|
||||
data.classLevelPermissions = schema.classLevelPermissions;
|
||||
data.indexes = schema.indexes;
|
||||
this.__data[schema.className] = data;
|
||||
}
|
||||
return this.__data[schema.className];
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// Inject the in-memory classes
|
||||
volatileClasses.forEach(className => {
|
||||
Object.defineProperty(this, className, {
|
||||
get: () => {
|
||||
if (!this.__data[className]) {
|
||||
const schema = injectDefaultSchema({
|
||||
className,
|
||||
fields: {},
|
||||
classLevelPermissions: {},
|
||||
});
|
||||
const data = {};
|
||||
data.fields = schema.fields;
|
||||
data.classLevelPermissions = schema.classLevelPermissions;
|
||||
data.indexes = schema.indexes;
|
||||
this.__data[className] = data;
|
||||
}
|
||||
return this.__data[className];
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const injectDefaultSchema = ({
|
||||
className,
|
||||
fields,
|
||||
@@ -469,21 +511,14 @@ const typeToString = (type: SchemaField | string): string => {
|
||||
// the mongo format and the Parse format. Soon, this will all be Parse format.
|
||||
export default class SchemaController {
|
||||
_dbAdapter: StorageAdapter;
|
||||
data: any;
|
||||
perms: any;
|
||||
indexes: any;
|
||||
schemaData: { [string]: Schema };
|
||||
_cache: any;
|
||||
reloadDataPromise: Promise<any>;
|
||||
|
||||
constructor(databaseAdapter: StorageAdapter, schemaCache: any) {
|
||||
this._dbAdapter = databaseAdapter;
|
||||
this._cache = schemaCache;
|
||||
// this.data[className][fieldName] tells you the type of that field, in mongo format
|
||||
this.data = {};
|
||||
// this.perms[className][operation] tells you the acl-style permissions
|
||||
this.perms = {};
|
||||
// this.indexes[className][operation] tells you the indexes
|
||||
this.indexes = {};
|
||||
this.schemaData = new SchemaData();
|
||||
}
|
||||
|
||||
reloadData(options: LoadSchemaOptions = { clearCache: false }): Promise<any> {
|
||||
@@ -500,35 +535,11 @@ export default class SchemaController {
|
||||
.then(() => {
|
||||
return this.getAllClasses(options).then(
|
||||
allSchemas => {
|
||||
const data = {};
|
||||
const perms = {};
|
||||
const indexes = {};
|
||||
allSchemas.forEach(schema => {
|
||||
data[schema.className] = injectDefaultSchema(schema).fields;
|
||||
perms[schema.className] = schema.classLevelPermissions;
|
||||
indexes[schema.className] = schema.indexes;
|
||||
});
|
||||
|
||||
// Inject the in-memory classes
|
||||
volatileClasses.forEach(className => {
|
||||
const schema = injectDefaultSchema({
|
||||
className,
|
||||
fields: {},
|
||||
classLevelPermissions: {},
|
||||
});
|
||||
data[className] = schema.fields;
|
||||
perms[className] = schema.classLevelPermissions;
|
||||
indexes[className] = schema.indexes;
|
||||
});
|
||||
this.data = data;
|
||||
this.perms = perms;
|
||||
this.indexes = indexes;
|
||||
this.schemaData = new SchemaData(allSchemas);
|
||||
delete this.reloadDataPromise;
|
||||
},
|
||||
err => {
|
||||
this.data = {};
|
||||
this.perms = {};
|
||||
this.indexes = {};
|
||||
this.schemaData = new SchemaData();
|
||||
delete this.reloadDataPromise;
|
||||
throw err;
|
||||
}
|
||||
@@ -575,11 +586,12 @@ export default class SchemaController {
|
||||
}
|
||||
return promise.then(() => {
|
||||
if (allowVolatileClasses && volatileClasses.indexOf(className) > -1) {
|
||||
const data = this.schemaData[className];
|
||||
return Promise.resolve({
|
||||
className,
|
||||
fields: this.data[className],
|
||||
classLevelPermissions: this.perms[className],
|
||||
indexes: this.indexes[className],
|
||||
fields: data.fields,
|
||||
classLevelPermissions: data.classLevelPermissions,
|
||||
indexes: data.indexes,
|
||||
});
|
||||
}
|
||||
return this._cache.getOneSchema(className).then(cached => {
|
||||
@@ -730,16 +742,14 @@ export default class SchemaController {
|
||||
.then(() => this.reloadData({ clearCache: true }))
|
||||
//TODO: Move this logic into the database adapter
|
||||
.then(() => {
|
||||
const schema = this.schemaData[className];
|
||||
const reloadedSchema: Schema = {
|
||||
className: className,
|
||||
fields: this.data[className],
|
||||
classLevelPermissions: this.perms[className],
|
||||
fields: schema.fields,
|
||||
classLevelPermissions: schema.classLevelPermissions,
|
||||
};
|
||||
if (
|
||||
this.indexes[className] &&
|
||||
Object.keys(this.indexes[className]).length !== 0
|
||||
) {
|
||||
reloadedSchema.indexes = this.indexes[className];
|
||||
if (schema.indexes && Object.keys(schema.indexes).length !== 0) {
|
||||
reloadedSchema.indexes = schema.indexes;
|
||||
}
|
||||
return reloadedSchema;
|
||||
})
|
||||
@@ -760,7 +770,7 @@ export default class SchemaController {
|
||||
// Returns a promise that resolves successfully to the new schema
|
||||
// object or fails with a reason.
|
||||
enforceClassExists(className: string): Promise<SchemaController> {
|
||||
if (this.data[className]) {
|
||||
if (this.schemaData[className]) {
|
||||
return Promise.resolve(this);
|
||||
}
|
||||
// We don't have this class. Update the schema
|
||||
@@ -777,7 +787,7 @@ export default class SchemaController {
|
||||
})
|
||||
.then(() => {
|
||||
// Ensure that the schema now validates
|
||||
if (this.data[className]) {
|
||||
if (this.schemaData[className]) {
|
||||
return this;
|
||||
} else {
|
||||
throw new Parse.Error(
|
||||
@@ -801,7 +811,7 @@ export default class SchemaController {
|
||||
fields: SchemaFields = {},
|
||||
classLevelPermissions: any
|
||||
): any {
|
||||
if (this.data[className]) {
|
||||
if (this.schemaData[className]) {
|
||||
throw new Parse.Error(
|
||||
Parse.Error.INVALID_CLASS_NAME,
|
||||
`Class ${className} already exists.`
|
||||
@@ -1114,11 +1124,15 @@ export default class SchemaController {
|
||||
|
||||
// Validates the base CLP for an operation
|
||||
testBaseCLP(className: string, aclGroup: string[], operation: string) {
|
||||
if (!this.perms[className] || !this.perms[className][operation]) {
|
||||
const classSchema = this.schemaData[className];
|
||||
if (
|
||||
!classSchema ||
|
||||
!classSchema.classLevelPermissions ||
|
||||
!classSchema.classLevelPermissions[operation]
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
const classPerms = this.perms[className];
|
||||
const perms = classPerms[operation];
|
||||
const perms = classSchema.classLevelPermissions[operation];
|
||||
// Handle the public scenario quickly
|
||||
if (perms['*']) {
|
||||
return true;
|
||||
@@ -1139,12 +1153,16 @@ export default class SchemaController {
|
||||
if (this.testBaseCLP(className, aclGroup, operation)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (!this.perms[className] || !this.perms[className][operation]) {
|
||||
const classSchema = this.schemaData[className];
|
||||
if (
|
||||
!classSchema ||
|
||||
!classSchema.classLevelPermissions ||
|
||||
!classSchema.classLevelPermissions[operation]
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
const classPerms = this.perms[className];
|
||||
const perms = classPerms[operation];
|
||||
const classPerms = classSchema.classLevelPermissions;
|
||||
const perms = classSchema.classLevelPermissions[operation];
|
||||
|
||||
// If only for authenticated users
|
||||
// make sure we have an aclGroup
|
||||
@@ -1200,8 +1218,8 @@ export default class SchemaController {
|
||||
className: string,
|
||||
fieldName: string
|
||||
): ?(SchemaField | string) {
|
||||
if (this.data && this.data[className]) {
|
||||
const expectedType = this.data[className][fieldName];
|
||||
if (this.schemaData[className]) {
|
||||
const expectedType = this.schemaData[className].fields[fieldName];
|
||||
return expectedType === 'map' ? 'Object' : expectedType;
|
||||
}
|
||||
return undefined;
|
||||
@@ -1209,7 +1227,7 @@ export default class SchemaController {
|
||||
|
||||
// Checks if a given class is in the schema.
|
||||
hasClass(className: string) {
|
||||
return this.reloadData().then(() => !!this.data[className]);
|
||||
return this.reloadData().then(() => !!this.schemaData[className]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user