Skip to content

Commit 6022149

Browse files
committed
Schema.js database agnostic
1 parent 99ecbb3 commit 6022149

File tree

7 files changed

+181
-163
lines changed

7 files changed

+181
-163
lines changed

spec/Schema.spec.js

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -685,9 +685,9 @@ describe('Schema', () => {
685685
.then(() => schema.reloadData())
686686
.then(() => {
687687
expect(schema['data']['NewClass']).toEqual({
688-
objectId: 'string',
689-
updatedAt: 'string',
690-
createdAt: 'string'
688+
objectId: { type: 'String' },
689+
updatedAt: { type: 'Date' },
690+
createdAt: { type: 'Date' }
691691
});
692692
done();
693693
});
@@ -747,7 +747,7 @@ describe('Schema', () => {
747747
it('can merge schemas', done => {
748748
expect(Schema.buildMergedSchemaObject({
749749
_id: 'SomeClass',
750-
someType: 'number'
750+
someType: { type: 'Number' }
751751
}, {
752752
newType: {type: 'Number'}
753753
})).toEqual({
@@ -760,8 +760,8 @@ describe('Schema', () => {
760760
it('can merge deletions', done => {
761761
expect(Schema.buildMergedSchemaObject({
762762
_id: 'SomeClass',
763-
someType: 'number',
764-
outDatedType: 'string',
763+
someType: { type: 'Number' },
764+
outDatedType: { type: 'String' },
765765
},{
766766
newType: {type: 'GeoPoint'},
767767
outDatedType: {__op: 'Delete'},
@@ -775,16 +775,16 @@ describe('Schema', () => {
775775
it('ignore default field when merge with system class', done => {
776776
expect(Schema.buildMergedSchemaObject({
777777
_id: '_User',
778-
username: 'string',
779-
password: 'string',
780-
authData: 'object',
781-
email: 'string',
782-
emailVerified: 'boolean'
778+
username: { type: 'String' },
779+
password: { type: 'String' },
780+
authData: { type: 'Object' },
781+
email: { type: 'String' },
782+
emailVerified: { type: 'Boolean' },
783783
},{
784-
authData: {type: 'string'},
785-
customField: {type: 'string'},
784+
authData: { type: 'String' },
785+
customField: { type: 'String' },
786786
})).toEqual({
787-
customField: {type: 'string'}
787+
customField: { type: 'String' }
788788
});
789789
done();
790790
});

spec/transform.spec.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ var dummySchema = {
88
data: {},
99
getExpectedType: function(className, key) {
1010
if (key == 'userPointer') {
11-
return '*_User';
11+
return { type: 'Pointer', targetClass: '_User' };
1212
} else if (key == 'picture') {
13-
return 'file';
13+
return { type: 'File' };
1414
} else if (key == 'location') {
15-
return 'geopoint';
15+
return { type: 'GeoPoint' };
1616
}
1717
return;
1818
},

src/Adapters/Storage/Mongo/MongoSchemaCollection.js

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,33 @@ function parseFieldTypeToMongoFieldType({ type, targetClass }) {
9393
}
9494
}
9595

96+
// Returns { code, error } if invalid, or { result }, an object
97+
// suitable for inserting into _SCHEMA collection, otherwise.
98+
function mongoSchemaFromFieldsAndClassNameAndCLP(fields, className, classLevelPermissions) {
99+
100+
let mongoObject = {
101+
_id: className,
102+
objectId: 'string',
103+
updatedAt: 'string',
104+
createdAt: 'string'
105+
};
106+
107+
for (let fieldName in fields) {
108+
mongoObject[fieldName] = parseFieldTypeToMongoFieldType(fields[fieldName]);
109+
}
110+
111+
if (typeof classLevelPermissions !== 'undefined') {
112+
mongoObject._metadata = mongoObject._metadata || {};
113+
if (!classLevelPermissions) {
114+
delete mongoObject._metadata.class_permissions;
115+
} else {
116+
mongoObject._metadata.class_permissions = classLevelPermissions;
117+
}
118+
}
119+
120+
return { result: mongoObject };
121+
}
122+
96123
class MongoSchemaCollection {
97124
_collection: MongoCollection;
98125

@@ -136,8 +163,12 @@ class MongoSchemaCollection {
136163
// later PR. Returns a promise that is expected to resolve with the newly created schema, in Parse format.
137164
// If the class already exists, returns a promise that rejects with undefined as the reason. If the collection
138165
// can't be added for a reason other than it already existing, requirements for rejection reason are TBD.
139-
addSchema(name: string, fields) {
140-
let mongoObject = _mongoSchemaObjectFromNameFields(name, fields);
166+
addSchema(name: string, fields, classLevelPermissions) {
167+
let mongoSchema = mongoSchemaFromFieldsAndClassNameAndCLP(fields, name, classLevelPermissions);
168+
if (!mongoSchema.result) {
169+
throw new Parse.Error(mongoSchema.code, mongoSchema.error);
170+
}
171+
let mongoObject = _mongoSchemaObjectFromNameFields(name, mongoSchema.result);
141172
return this._collection.insertOne(mongoObject)
142173
.then(result => mongoSchemaToParseSchema(result.ops[0]))
143174
.catch(error => {
@@ -155,18 +186,27 @@ class MongoSchemaCollection {
155186
upsertSchema(name: string, query: string, update) {
156187
return this._collection.upsertOne(_mongoSchemaQueryFromNameQuery(name, query), update);
157188
}
189+
190+
updateField(className: string, fieldName: string, type: string) {
191+
// We don't have this field. Update the schema.
192+
// Note that we use the $exists guard and $set to avoid race
193+
// conditions in the database. This is important!
194+
let query = {};
195+
query[fieldName] = { '$exists': false };
196+
let update = {};
197+
if (typeof type === 'string') {
198+
type = {
199+
type: type
200+
}
201+
}
202+
update[fieldName] = parseFieldTypeToMongoFieldType(type);
203+
update = {'$set': update};
204+
return this.upsertSchema(className, query, update);
205+
}
158206
}
159207

160208
// Exported for testing reasons and because we haven't moved all mongo schema format
161209
// related logic into the database adapter yet.
162210
MongoSchemaCollection._TESTmongoSchemaToParseSchema = mongoSchemaToParseSchema
163211

164-
// Exported because we haven't moved all mongo schema format related logic
165-
// into the database adapter yet. We will remove this before too long.
166-
MongoSchemaCollection._DONOTUSEmongoFieldToParseSchemaField = mongoFieldToParseSchemaField
167-
168-
// Exported because we haven't moved all mongo schema format related logic
169-
// into the database adapter yet. We will remove this before too long.
170-
MongoSchemaCollection._DONOTUSEparseFieldTypeToMongoFieldType = parseFieldTypeToMongoFieldType;
171-
172212
export default MongoSchemaCollection

src/Controllers/DatabaseController.js

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,8 @@ DatabaseController.prototype.loadSchema = function(acceptor = returnsTrue) {
9090
DatabaseController.prototype.redirectClassNameForKey = function(className, key) {
9191
return this.loadSchema().then((schema) => {
9292
var t = schema.getExpectedType(className, key);
93-
var match = t ? t.match(/^relation<(.*)>$/) : false;
94-
if (match) {
95-
return match[1];
93+
if (t.type == 'Relation') {
94+
return t.targetClass;
9695
} else {
9796
return className;
9897
}
@@ -446,11 +445,10 @@ DatabaseController.prototype.reduceInRelation = function(className, query, schem
446445
let promises = Object.keys(query).map((key) => {
447446
if (query[key] && (query[key]['$in'] || query[key]['$ne'] || query[key]['$nin'] || query[key].__type == 'Pointer')) {
448447
let t = schema.getExpectedType(className, key);
449-
let match = t ? t.match(/^relation<(.*)>$/) : false;
450-
if (!match) {
448+
if (!t || t.type !== 'Relation') {
451449
return Promise.resolve(query);
452450
}
453-
let relatedClassName = match[1];
451+
let relatedClassName = t.targetClass;
454452
// Build the list of queries
455453
let queries = Object.keys(query[key]).map((constraintKey) => {
456454
let relatedIds;
@@ -599,7 +597,6 @@ DatabaseController.prototype.find = function(className, query, options = {}) {
599597
if (options.limit) {
600598
mongoOptions.limit = options.limit;
601599
}
602-
603600
let isMaster = !('acl' in options);
604601
let aclGroup = options.acl || [];
605602
let acceptor = schema => schema.hasKeys(className, keysForQuery(query))

0 commit comments

Comments
 (0)