ParseSchema.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. /**
  2. * Copyright (c) 2015-present, Parse, LLC.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. *
  9. * @flow
  10. */
  11. import CoreManager from './CoreManager';
  12. /*:: import type { RequestOptions, FullOptions } from './RESTController';*/
  13. const FIELD_TYPES = ['String', 'Number', 'Boolean', 'Date', 'File', 'GeoPoint', 'Polygon', 'Array', 'Object', 'Pointer', 'Relation'];
  14. /**
  15. * A Parse.Schema object is for handling schema data from Parse.
  16. * <p>All the schemas methods require MasterKey.
  17. *
  18. * <pre>
  19. * const schema = new Parse.Schema('MyClass');
  20. * schema.addString('field');
  21. * schema.addIndex('index_name', {'field', 1});
  22. * schema.save();
  23. * </pre>
  24. * </p>
  25. * @alias Parse.Schema
  26. */
  27. class ParseSchema {
  28. /*:: className: string;*/
  29. /*:: _fields: { [key: string]: mixed };*/
  30. /*:: _indexes: { [key: string]: mixed };*/
  31. /**
  32. * @param {String} className Parse Class string.
  33. */
  34. constructor(className
  35. /*: string*/
  36. ) {
  37. if (typeof className === 'string') {
  38. if (className === 'User' && CoreManager.get('PERFORM_USER_REWRITE')) {
  39. this.className = '_User';
  40. } else {
  41. this.className = className;
  42. }
  43. }
  44. this._fields = {};
  45. this._indexes = {};
  46. }
  47. /**
  48. * Static method to get all schemas
  49. *
  50. * @param {Object} options
  51. * Valid options are:<ul>
  52. * <li>useMasterKey: In Cloud Code and Node only, causes the Master Key to
  53. * be used for this request.
  54. * <li>sessionToken: A valid session token, used for making a request on
  55. * behalf of a specific user.
  56. * </ul>
  57. *
  58. * @return {Promise} A promise that is resolved with the result when
  59. * the query completes.
  60. */
  61. static all(options
  62. /*: FullOptions*/
  63. ) {
  64. options = options || {};
  65. const controller = CoreManager.getSchemaController();
  66. return controller.get('', options).then(response => {
  67. if (response.results.length === 0) {
  68. throw new Error('Schema not found.');
  69. }
  70. return response.results;
  71. });
  72. }
  73. /**
  74. * Get the Schema from Parse
  75. *
  76. * @param {Object} options
  77. * Valid options are:<ul>
  78. * <li>useMasterKey: In Cloud Code and Node only, causes the Master Key to
  79. * be used for this request.
  80. * <li>sessionToken: A valid session token, used for making a request on
  81. * behalf of a specific user.
  82. * </ul>
  83. *
  84. * @return {Promise} A promise that is resolved with the result when
  85. * the query completes.
  86. */
  87. get(options
  88. /*: FullOptions*/
  89. ) {
  90. this.assertClassName();
  91. options = options || {};
  92. const controller = CoreManager.getSchemaController();
  93. return controller.get(this.className, options).then(response => {
  94. if (!response) {
  95. throw new Error('Schema not found.');
  96. }
  97. return response;
  98. });
  99. }
  100. /**
  101. * Create a new Schema on Parse
  102. *
  103. * @param {Object} options
  104. * Valid options are:<ul>
  105. * <li>useMasterKey: In Cloud Code and Node only, causes the Master Key to
  106. * be used for this request.
  107. * <li>sessionToken: A valid session token, used for making a request on
  108. * behalf of a specific user.
  109. * </ul>
  110. *
  111. * @return {Promise} A promise that is resolved with the result when
  112. * the query completes.
  113. */
  114. save(options
  115. /*: FullOptions*/
  116. ) {
  117. this.assertClassName();
  118. options = options || {};
  119. const controller = CoreManager.getSchemaController();
  120. const params = {
  121. className: this.className,
  122. fields: this._fields,
  123. indexes: this._indexes
  124. };
  125. return controller.create(this.className, params, options).then(response => {
  126. return response;
  127. });
  128. }
  129. /**
  130. * Update a Schema on Parse
  131. *
  132. * @param {Object} options
  133. * Valid options are:<ul>
  134. * <li>useMasterKey: In Cloud Code and Node only, causes the Master Key to
  135. * be used for this request.
  136. * <li>sessionToken: A valid session token, used for making a request on
  137. * behalf of a specific user.
  138. * </ul>
  139. *
  140. * @return {Promise} A promise that is resolved with the result when
  141. * the query completes.
  142. */
  143. update(options
  144. /*: FullOptions*/
  145. ) {
  146. this.assertClassName();
  147. options = options || {};
  148. const controller = CoreManager.getSchemaController();
  149. const params = {
  150. className: this.className,
  151. fields: this._fields,
  152. indexes: this._indexes
  153. };
  154. this._fields = {};
  155. this._indexes = {};
  156. return controller.update(this.className, params, options).then(response => {
  157. return response;
  158. });
  159. }
  160. /**
  161. * Removing a Schema from Parse
  162. * Can only be used on Schema without objects
  163. *
  164. * @param {Object} options
  165. * Valid options are:<ul>
  166. * <li>useMasterKey: In Cloud Code and Node only, causes the Master Key to
  167. * be used for this request.
  168. * <li>sessionToken: A valid session token, used for making a request on
  169. * behalf of a specific user.
  170. * </ul>
  171. *
  172. * @return {Promise} A promise that is resolved with the result when
  173. * the query completes.
  174. */
  175. delete(options
  176. /*: FullOptions*/
  177. ) {
  178. this.assertClassName();
  179. options = options || {};
  180. const controller = CoreManager.getSchemaController();
  181. return controller.delete(this.className, options).then(response => {
  182. return response;
  183. });
  184. }
  185. /**
  186. * Removes all objects from a Schema (class) in Parse.
  187. * EXERCISE CAUTION, running this will delete all objects for this schema and cannot be reversed
  188. * @return {Promise} A promise that is resolved with the result when
  189. * the query completes.
  190. */
  191. purge() {
  192. this.assertClassName();
  193. const controller = CoreManager.getSchemaController();
  194. return controller.purge(this.className).then(response => {
  195. return response;
  196. });
  197. }
  198. /**
  199. * Assert if ClassName has been filled
  200. * @private
  201. */
  202. assertClassName() {
  203. if (!this.className) {
  204. throw new Error('You must set a Class Name before making any request.');
  205. }
  206. }
  207. /**
  208. * Adding a Field to Create / Update a Schema
  209. *
  210. * @param {String} name Name of the field that will be created on Parse
  211. * @param {String} type TheCan be a (String|Number|Boolean|Date|Parse.File|Parse.GeoPoint|Array|Object|Pointer|Parse.Relation)
  212. * @return {Parse.Schema} Returns the schema, so you can chain this call.
  213. */
  214. addField(name
  215. /*: string*/
  216. , type
  217. /*: string*/
  218. ) {
  219. type = type || 'String';
  220. if (!name) {
  221. throw new Error('field name may not be null.');
  222. }
  223. if (FIELD_TYPES.indexOf(type) === -1) {
  224. throw new Error(`${type} is not a valid type.`);
  225. }
  226. this._fields[name] = {
  227. type
  228. };
  229. return this;
  230. }
  231. /**
  232. * Adding an Index to Create / Update a Schema
  233. *
  234. * @param {String} name Name of the field that will be created on Parse
  235. * @param {String} type Can be a (String|Number|Boolean|Date|Parse.File|Parse.GeoPoint|Array|Object|Pointer|Parse.Relation)
  236. * @return {Parse.Schema} Returns the schema, so you can chain this call.
  237. */
  238. addIndex(name
  239. /*: string*/
  240. , index
  241. /*: any*/
  242. ) {
  243. if (!name) {
  244. throw new Error('index name may not be null.');
  245. }
  246. if (!index) {
  247. throw new Error('index may not be null.');
  248. }
  249. this._indexes[name] = index;
  250. return this;
  251. }
  252. /**
  253. * Adding String Field
  254. *
  255. * @param {String} name Name of the field that will be created on Parse
  256. * @return {Parse.Schema} Returns the schema, so you can chain this call.
  257. */
  258. addString(name
  259. /*: string*/
  260. ) {
  261. return this.addField(name, 'String');
  262. }
  263. /**
  264. * Adding Number Field
  265. *
  266. * @param {String} name Name of the field that will be created on Parse
  267. * @return {Parse.Schema} Returns the schema, so you can chain this call.
  268. */
  269. addNumber(name
  270. /*: string*/
  271. ) {
  272. return this.addField(name, 'Number');
  273. }
  274. /**
  275. * Adding Boolean Field
  276. *
  277. * @param {String} name Name of the field that will be created on Parse
  278. * @return {Parse.Schema} Returns the schema, so you can chain this call.
  279. */
  280. addBoolean(name
  281. /*: string*/
  282. ) {
  283. return this.addField(name, 'Boolean');
  284. }
  285. /**
  286. * Adding Date Field
  287. *
  288. * @param {String} name Name of the field that will be created on Parse
  289. * @return {Parse.Schema} Returns the schema, so you can chain this call.
  290. */
  291. addDate(name
  292. /*: string*/
  293. ) {
  294. return this.addField(name, 'Date');
  295. }
  296. /**
  297. * Adding File Field
  298. *
  299. * @param {String} name Name of the field that will be created on Parse
  300. * @return {Parse.Schema} Returns the schema, so you can chain this call.
  301. */
  302. addFile(name
  303. /*: string*/
  304. ) {
  305. return this.addField(name, 'File');
  306. }
  307. /**
  308. * Adding GeoPoint Field
  309. *
  310. * @param {String} name Name of the field that will be created on Parse
  311. * @return {Parse.Schema} Returns the schema, so you can chain this call.
  312. */
  313. addGeoPoint(name
  314. /*: string*/
  315. ) {
  316. return this.addField(name, 'GeoPoint');
  317. }
  318. /**
  319. * Adding Polygon Field
  320. *
  321. * @param {String} name Name of the field that will be created on Parse
  322. * @return {Parse.Schema} Returns the schema, so you can chain this call.
  323. */
  324. addPolygon(name
  325. /*: string*/
  326. ) {
  327. return this.addField(name, 'Polygon');
  328. }
  329. /**
  330. * Adding Array Field
  331. *
  332. * @param {String} name Name of the field that will be created on Parse
  333. * @return {Parse.Schema} Returns the schema, so you can chain this call.
  334. */
  335. addArray(name
  336. /*: string*/
  337. ) {
  338. return this.addField(name, 'Array');
  339. }
  340. /**
  341. * Adding Object Field
  342. *
  343. * @param {String} name Name of the field that will be created on Parse
  344. * @return {Parse.Schema} Returns the schema, so you can chain this call.
  345. */
  346. addObject(name
  347. /*: string*/
  348. ) {
  349. return this.addField(name, 'Object');
  350. }
  351. /**
  352. * Adding Pointer Field
  353. *
  354. * @param {String} name Name of the field that will be created on Parse
  355. * @param {String} targetClass Name of the target Pointer Class
  356. * @return {Parse.Schema} Returns the schema, so you can chain this call.
  357. */
  358. addPointer(name
  359. /*: string*/
  360. , targetClass
  361. /*: string*/
  362. ) {
  363. if (!name) {
  364. throw new Error('field name may not be null.');
  365. }
  366. if (!targetClass) {
  367. throw new Error('You need to set the targetClass of the Pointer.');
  368. }
  369. this._fields[name] = {
  370. type: 'Pointer',
  371. targetClass
  372. };
  373. return this;
  374. }
  375. /**
  376. * Adding Relation Field
  377. *
  378. * @param {String} name Name of the field that will be created on Parse
  379. * @param {String} targetClass Name of the target Pointer Class
  380. * @return {Parse.Schema} Returns the schema, so you can chain this call.
  381. */
  382. addRelation(name
  383. /*: string*/
  384. , targetClass
  385. /*: string*/
  386. ) {
  387. if (!name) {
  388. throw new Error('field name may not be null.');
  389. }
  390. if (!targetClass) {
  391. throw new Error('You need to set the targetClass of the Relation.');
  392. }
  393. this._fields[name] = {
  394. type: 'Relation',
  395. targetClass
  396. };
  397. return this;
  398. }
  399. /**
  400. * Deleting a Field to Update on a Schema
  401. *
  402. * @param {String} name Name of the field that will be created on Parse
  403. * @param {String} targetClass Name of the target Pointer Class
  404. * @return {Parse.Schema} Returns the schema, so you can chain this call.
  405. */
  406. deleteField(name
  407. /*: string*/
  408. ) {
  409. this._fields[name] = {
  410. __op: 'Delete'
  411. };
  412. }
  413. /**
  414. * Deleting an Index to Update on a Schema
  415. *
  416. * @param {String} name Name of the field that will be created on Parse
  417. * @param {String} targetClass Name of the target Pointer Class
  418. * @return {Parse.Schema} Returns the schema, so you can chain this call.
  419. */
  420. deleteIndex(name
  421. /*: string*/
  422. ) {
  423. this._indexes[name] = {
  424. __op: 'Delete'
  425. };
  426. }
  427. }
  428. const DefaultController = {
  429. send(className
  430. /*: string*/
  431. , method
  432. /*: string*/
  433. , params
  434. /*: any*/
  435. , options
  436. /*: RequestOptions*/
  437. )
  438. /*: Promise*/
  439. {
  440. const RESTController = CoreManager.getRESTController();
  441. const requestOptions = {
  442. useMasterKey: true
  443. };
  444. if (options.hasOwnProperty('sessionToken')) {
  445. requestOptions.sessionToken = options.sessionToken;
  446. }
  447. return RESTController.request(method, `schemas/${className}`, params, requestOptions);
  448. },
  449. get(className
  450. /*: string*/
  451. , options
  452. /*: RequestOptions*/
  453. )
  454. /*: Promise*/
  455. {
  456. return this.send(className, 'GET', {}, options);
  457. },
  458. create(className
  459. /*: string*/
  460. , params
  461. /*: any*/
  462. , options
  463. /*: RequestOptions*/
  464. )
  465. /*: Promise*/
  466. {
  467. return this.send(className, 'POST', params, options);
  468. },
  469. update(className
  470. /*: string*/
  471. , params
  472. /*: any*/
  473. , options
  474. /*: RequestOptions*/
  475. )
  476. /*: Promise*/
  477. {
  478. return this.send(className, 'PUT', params, options);
  479. },
  480. delete(className
  481. /*: string*/
  482. , options
  483. /*: RequestOptions*/
  484. )
  485. /*: Promise*/
  486. {
  487. return this.send(className, 'DELETE', {}, options);
  488. },
  489. purge(className
  490. /*: string*/
  491. )
  492. /*: Promise*/
  493. {
  494. const RESTController = CoreManager.getRESTController();
  495. return RESTController.request('DELETE', `purge/${className}`, {}, {
  496. useMasterKey: true
  497. });
  498. }
  499. };
  500. CoreManager.setSchemaController(DefaultController);
  501. export default ParseSchema;