ParseRelation.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  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 { RelationOp } from './ParseOp';
  12. import ParseObject from './ParseObject';
  13. import ParseQuery from './ParseQuery';
  14. /**
  15. * Creates a new Relation for the given parent object and key. This
  16. * constructor should rarely be used directly, but rather created by
  17. * Parse.Object.relation.
  18. *
  19. * <p>
  20. * A class that is used to access all of the children of a many-to-many
  21. * relationship. Each instance of Parse.Relation is associated with a
  22. * particular parent object and key.
  23. * </p>
  24. * @alias Parse.Relation
  25. */
  26. class ParseRelation {
  27. /*:: parent: ?ParseObject;*/
  28. /*:: key: ?string;*/
  29. /*:: targetClassName: ?string;*/
  30. /**
  31. * @param {Parse.Object} parent The parent of this relation.
  32. * @param {String} key The key for this relation on the parent.
  33. */
  34. constructor(parent
  35. /*: ?ParseObject*/
  36. , key
  37. /*: ?string*/
  38. ) {
  39. this.parent = parent;
  40. this.key = key;
  41. this.targetClassName = null;
  42. }
  43. /*
  44. * Makes sure that this relation has the right parent and key.
  45. */
  46. _ensureParentAndKey(parent
  47. /*: ParseObject*/
  48. , key
  49. /*: string*/
  50. ) {
  51. this.key = this.key || key;
  52. if (this.key !== key) {
  53. throw new Error('Internal Error. Relation retrieved from two different keys.');
  54. }
  55. if (this.parent) {
  56. if (this.parent.className !== parent.className) {
  57. throw new Error('Internal Error. Relation retrieved from two different Objects.');
  58. }
  59. if (this.parent.id) {
  60. if (this.parent.id !== parent.id) {
  61. throw new Error('Internal Error. Relation retrieved from two different Objects.');
  62. }
  63. } else if (parent.id) {
  64. this.parent = parent;
  65. }
  66. } else {
  67. this.parent = parent;
  68. }
  69. }
  70. /**
  71. * Adds a Parse.Object or an array of Parse.Objects to the relation.
  72. * @param {} objects The item or items to add.
  73. */
  74. add(objects
  75. /*: ParseObject | Array<ParseObject | string>*/
  76. )
  77. /*: ParseObject*/
  78. {
  79. if (!Array.isArray(objects)) {
  80. objects = [objects];
  81. }
  82. const change = new RelationOp(objects, []);
  83. const parent = this.parent;
  84. if (!parent) {
  85. throw new Error('Cannot add to a Relation without a parent');
  86. }
  87. parent.set(this.key, change);
  88. this.targetClassName = change._targetClassName;
  89. return parent;
  90. }
  91. /**
  92. * Removes a Parse.Object or an array of Parse.Objects from this relation.
  93. * @param {} objects The item or items to remove.
  94. */
  95. remove(objects
  96. /*: ParseObject | Array<ParseObject | string>*/
  97. ) {
  98. if (!Array.isArray(objects)) {
  99. objects = [objects];
  100. }
  101. const change = new RelationOp([], objects);
  102. if (!this.parent) {
  103. throw new Error('Cannot remove from a Relation without a parent');
  104. }
  105. this.parent.set(this.key, change);
  106. this.targetClassName = change._targetClassName;
  107. }
  108. /**
  109. * Returns a JSON version of the object suitable for saving to disk.
  110. * @return {Object}
  111. */
  112. toJSON()
  113. /*: { __type: 'Relation', className: ?string }*/
  114. {
  115. return {
  116. __type: 'Relation',
  117. className: this.targetClassName
  118. };
  119. }
  120. /**
  121. * Returns a Parse.Query that is limited to objects in this
  122. * relation.
  123. * @return {Parse.Query}
  124. */
  125. query()
  126. /*: ParseQuery*/
  127. {
  128. let query;
  129. const parent = this.parent;
  130. if (!parent) {
  131. throw new Error('Cannot construct a query for a Relation without a parent');
  132. }
  133. if (!this.targetClassName) {
  134. query = new ParseQuery(parent.className);
  135. query._extraOptions.redirectClassNameForKey = this.key;
  136. } else {
  137. query = new ParseQuery(this.targetClassName);
  138. }
  139. query._addCondition('$relatedTo', 'object', {
  140. __type: 'Pointer',
  141. className: parent.className,
  142. objectId: parent.id
  143. });
  144. query._addCondition('$relatedTo', 'key', this.key);
  145. return query;
  146. }
  147. }
  148. export default ParseRelation;