unsavedChildren.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = unsavedChildren;
  6. var _ParseFile = _interopRequireDefault(require("./ParseFile"));
  7. var _ParseObject = _interopRequireDefault(require("./ParseObject"));
  8. var _ParseRelation = _interopRequireDefault(require("./ParseRelation"));
  9. function _interopRequireDefault(obj) {
  10. return obj && obj.__esModule ? obj : {
  11. default: obj
  12. };
  13. }
  14. /**
  15. * Copyright (c) 2015-present, Parse, LLC.
  16. * All rights reserved.
  17. *
  18. * This source code is licensed under the BSD-style license found in the
  19. * LICENSE file in the root directory of this source tree. An additional grant
  20. * of patent rights can be found in the PATENTS file in the same directory.
  21. *
  22. * @flow
  23. */
  24. /**
  25. * Return an array of unsaved children, which are either Parse Objects or Files.
  26. * If it encounters any dirty Objects without Ids, it will throw an exception.
  27. *
  28. * @param {Parse.Object} obj
  29. * @param {boolean} allowDeepUnsaved
  30. * @returns {Array}
  31. */
  32. function unsavedChildren(obj
  33. /*: ParseObject*/
  34. , allowDeepUnsaved
  35. /*:: ?: boolean*/
  36. )
  37. /*: Array<ParseFile | ParseObject>*/
  38. {
  39. const encountered = {
  40. objects: {},
  41. files: []
  42. };
  43. const identifier = `${obj.className}:${obj._getId()}`;
  44. encountered.objects[identifier] = obj.dirty() ? obj : true;
  45. const {
  46. attributes
  47. } = obj;
  48. for (const attr in attributes) {
  49. if (typeof attributes[attr] === 'object') {
  50. traverse(attributes[attr], encountered, false, !!allowDeepUnsaved);
  51. }
  52. }
  53. const unsaved = [];
  54. for (const id in encountered.objects) {
  55. if (id !== identifier && encountered.objects[id] !== true) {
  56. unsaved.push(encountered.objects[id]);
  57. }
  58. }
  59. return unsaved.concat(encountered.files);
  60. }
  61. function traverse(obj
  62. /*: ParseObject*/
  63. , encountered
  64. /*: EncounterMap*/
  65. , shouldThrow
  66. /*: boolean*/
  67. , allowDeepUnsaved
  68. /*: boolean*/
  69. ) {
  70. if (obj instanceof _ParseObject.default) {
  71. if (!obj.id && shouldThrow) {
  72. throw new Error('Cannot create a pointer to an unsaved Object.');
  73. }
  74. const identifier = `${obj.className}:${obj._getId()}`;
  75. if (!encountered.objects[identifier]) {
  76. encountered.objects[identifier] = obj.dirty() ? obj : true;
  77. const {
  78. attributes
  79. } = obj;
  80. for (const attr in attributes) {
  81. if (typeof attributes[attr] === 'object') {
  82. traverse(attributes[attr], encountered, !allowDeepUnsaved, allowDeepUnsaved);
  83. }
  84. }
  85. }
  86. return;
  87. }
  88. if (obj instanceof _ParseFile.default) {
  89. if (!obj.url() && encountered.files.indexOf(obj) < 0) {
  90. encountered.files.push(obj);
  91. }
  92. return;
  93. }
  94. if (obj instanceof _ParseRelation.default) {
  95. return;
  96. }
  97. if (Array.isArray(obj)) {
  98. obj.forEach(el => {
  99. if (typeof el === 'object') {
  100. traverse(el, encountered, shouldThrow, allowDeepUnsaved);
  101. }
  102. });
  103. }
  104. for (const k in obj) {
  105. if (typeof obj[k] === 'object') {
  106. traverse(obj[k], encountered, shouldThrow, allowDeepUnsaved);
  107. }
  108. }
  109. }