diff --git a/spec/MongoSchemaCollectionAdapter.spec.js b/spec/MongoSchemaCollectionAdapter.spec.js index 8e376b9d1d..4d564591ac 100644 --- a/spec/MongoSchemaCollectionAdapter.spec.js +++ b/spec/MongoSchemaCollectionAdapter.spec.js @@ -96,4 +96,111 @@ describe('MongoSchemaCollection', () => { }); done(); }); + + describe('mongoFieldToParseSchemaField function', () => { + // Test successful type conversions + it('should convert valid mongo field types to parse schema fields', () => { + const testCases = [ + { input: 'string', expected: { type: 'String' } }, + { input: 'number', expected: { type: 'Number' } }, + { input: 'boolean', expected: { type: 'Boolean' } }, + { input: 'date', expected: { type: 'Date' } }, + { input: 'map', expected: { type: 'Object' } }, + { input: 'object', expected: { type: 'Object' } }, + { input: 'array', expected: { type: 'Array' } }, + { input: 'geopoint', expected: { type: 'GeoPoint' } }, + { input: 'file', expected: { type: 'File' } }, + { input: 'bytes', expected: { type: 'Bytes' } }, + { input: 'polygon', expected: { type: 'Polygon' } }, + { input: '*_User', expected: { type: 'Pointer', targetClass: '_User' } }, + { input: '*Post', expected: { type: 'Pointer', targetClass: 'Post' } }, + { input: 'relation<_User>', expected: { type: 'Relation', targetClass: '_User' } }, + { input: 'relation', expected: { type: 'Relation', targetClass: 'Post' } }, + ]; + + testCases.forEach(({ input, expected }) => { + const result = MongoSchemaCollection._TESTmongoSchemaToParseSchema({ + _id: 'TestClass', + testField: input, + }); + + expect(result.fields.testField).toEqual(expected); + }); + }); + + // Test error handling for invalid types (non-string values) + it('should throw error for invalid field types', () => { + const invalidInputs = [ + null, + undefined, + 123, + true, + false, + {}, + [], + '', + ]; + + invalidInputs.forEach(invalidInput => { + expect(() => { + MongoSchemaCollection._TESTmongoSchemaToParseSchema({ + _id: 'TestClass', + testField: invalidInput, + }); + }).toThrow(); + }); + }); + + it('should throw error with correct message for null input', () => { + try { + MongoSchemaCollection._TESTmongoSchemaToParseSchema({ + _id: 'TestClass', + testField: null, + }); + } catch (error) { + expect(error.code).toBe(255); + expect(error.message).toContain('Invalid field type'); + expect(error.message).toContain('Expected a string'); + } + }); + + it('should throw error with correct message for undefined input', () => { + try { + MongoSchemaCollection._TESTmongoSchemaToParseSchema({ + _id: 'TestClass', + testField: undefined, + }); + } catch (error) { + expect(error.code).toBe(255); + expect(error.message).toContain('Invalid field type'); + expect(error.message).toContain('Expected a string'); + } + }); + + it('should throw error with correct message for non-string input', () => { + try { + MongoSchemaCollection._TESTmongoSchemaToParseSchema({ + _id: 'TestClass', + testField: 123, + }); + } catch (error) { + expect(error.code).toBe(255); + expect(error.message).toContain('Invalid field type'); + expect(error.message).toContain('Expected a string'); + } + }); + + it('should throw error with correct message for empty string input', () => { + try { + MongoSchemaCollection._TESTmongoSchemaToParseSchema({ + _id: 'TestClass', + testField: '', + }); + } catch (error) { + expect(error.code).toBe(255); + expect(error.message).toContain('Invalid field type'); + expect(error.message).toContain('Expected a string'); + } + }); + }); }); diff --git a/src/Adapters/Storage/Mongo/MongoSchemaCollection.js b/src/Adapters/Storage/Mongo/MongoSchemaCollection.js index 45b27f7516..17bc5c9516 100644 --- a/src/Adapters/Storage/Mongo/MongoSchemaCollection.js +++ b/src/Adapters/Storage/Mongo/MongoSchemaCollection.js @@ -1,7 +1,15 @@ import MongoCollection from './MongoCollection'; import Parse from 'parse/node'; -function mongoFieldToParseSchemaField(type) { +function mongoFieldToParseSchemaField(type, fieldName, className) { + // Add type validation to prevent TypeError + if (!type || typeof type !== 'string') { + throw new Parse.Error( + Parse.Error.INVALID_SCHEMA_OPERATION, + `Invalid field type: ${type} for field '${fieldName}' in class '_SCHEMA' (id: ${className}). Expected a string. Fix the type mismatch in your schema configuration.` + ); + } + if (type[0] === '*') { return { type: 'Pointer', @@ -43,7 +51,7 @@ const nonFieldSchemaKeys = ['_id', '_metadata', '_client_permissions']; function mongoSchemaFieldsToParseSchemaFields(schema) { var fieldNames = Object.keys(schema).filter(key => nonFieldSchemaKeys.indexOf(key) === -1); var response = fieldNames.reduce((obj, fieldName) => { - obj[fieldName] = mongoFieldToParseSchemaField(schema[fieldName]); + obj[fieldName] = mongoFieldToParseSchemaField(schema[fieldName], fieldName, schema._id); if ( schema._metadata && schema._metadata.fields_options &&