becca_entities_attribute.js.html 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <title>JSDoc: Source: becca/entities/attribute.js</title>
  6. <script src="scripts/prettify/prettify.js"> </script>
  7. <script src="scripts/prettify/lang-css.js"> </script>
  8. <!--[if lt IE 9]>
  9. <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
  10. <![endif]-->
  11. <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
  12. <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
  13. </head>
  14. <body>
  15. <div id="main">
  16. <h1 class="page-title">Source: becca/entities/attribute.js</h1>
  17. <section>
  18. <article>
  19. <pre class="prettyprint source linenums"><code>"use strict";
  20. const Note = require('./note');
  21. const AbstractEntity = require("./abstract_entity");
  22. const sql = require("../../services/sql");
  23. const dateUtils = require("../../services/date_utils");
  24. const promotedAttributeDefinitionParser = require("../../services/promoted_attribute_definition_parser");
  25. /**
  26. * Attribute is an abstract concept which has two real uses - label (key - value pair)
  27. * and relation (representing named relationship between source and target note)
  28. */
  29. class Attribute extends AbstractEntity {
  30. static get entityName() { return "attributes"; }
  31. static get primaryKeyName() { return "attributeId"; }
  32. static get hashedProperties() { return ["attributeId", "noteId", "type", "name", "value", "isInheritable"]; }
  33. constructor(row) {
  34. super();
  35. if (!row) {
  36. return;
  37. }
  38. this.updateFromRow(row);
  39. this.init();
  40. }
  41. updateFromRow(row) {
  42. this.update([
  43. row.attributeId,
  44. row.noteId,
  45. row.type,
  46. row.name,
  47. row.value,
  48. row.isInheritable,
  49. row.position,
  50. row.utcDateModified
  51. ]);
  52. }
  53. update([attributeId, noteId, type, name, value, isInheritable, position, utcDateModified]) {
  54. /** @type {string} */
  55. this.attributeId = attributeId;
  56. /** @type {string} */
  57. this.noteId = noteId;
  58. /** @type {string} */
  59. this.type = type;
  60. /** @type {string} */
  61. this.name = name;
  62. /** @type {int} */
  63. this.position = position;
  64. /** @type {string} */
  65. this.value = value || "";
  66. /** @type {boolean} */
  67. this.isInheritable = !!isInheritable;
  68. /** @type {string} */
  69. this.utcDateModified = utcDateModified;
  70. return this;
  71. }
  72. init() {
  73. if (this.attributeId) {
  74. this.becca.attributes[this.attributeId] = this;
  75. }
  76. if (!(this.noteId in this.becca.notes)) {
  77. // entities can come out of order in sync, create skeleton which will be filled later
  78. this.becca.addNote(this.noteId, new Note({noteId: this.noteId}));
  79. }
  80. this.becca.notes[this.noteId].ownedAttributes.push(this);
  81. const key = `${this.type}-${this.name.toLowerCase()}`;
  82. this.becca.attributeIndex[key] = this.becca.attributeIndex[key] || [];
  83. this.becca.attributeIndex[key].push(this);
  84. const targetNote = this.targetNote;
  85. if (targetNote) {
  86. targetNote.targetRelations.push(this);
  87. }
  88. }
  89. get isAffectingSubtree() {
  90. return this.isInheritable
  91. || (this.type === 'relation' &amp;&amp; this.name === 'template');
  92. }
  93. get targetNoteId() { // alias
  94. return this.type === 'relation' ? this.value : undefined;
  95. }
  96. isAutoLink() {
  97. return this.type === 'relation' &amp;&amp; ['internalLink', 'imageLink', 'relationMapLink', 'includeNoteLink'].includes(this.name);
  98. }
  99. get note() {
  100. return this.becca.notes[this.noteId];
  101. }
  102. get targetNote() {
  103. if (this.type === 'relation') {
  104. return this.becca.notes[this.value];
  105. }
  106. }
  107. /**
  108. * @returns {Note|null}
  109. */
  110. getNote() {
  111. return this.becca.getNote(this.noteId);
  112. }
  113. /**
  114. * @returns {Note|null}
  115. */
  116. getTargetNote() {
  117. if (this.type !== 'relation') {
  118. throw new Error(`Attribute ${this.attributeId} is not relation`);
  119. }
  120. if (!this.value) {
  121. return null;
  122. }
  123. return this.becca.getNote(this.value);
  124. }
  125. /**
  126. * @return {boolean}
  127. */
  128. isDefinition() {
  129. return this.type === 'label' &amp;&amp; (this.name.startsWith('label:') || this.name.startsWith('relation:'));
  130. }
  131. getDefinition() {
  132. return promotedAttributeDefinitionParser.parse(this.value);
  133. }
  134. getDefinedName() {
  135. if (this.type === 'label' &amp;&amp; this.name.startsWith('label:')) {
  136. return this.name.substr(6);
  137. } else if (this.type === 'label' &amp;&amp; this.name.startsWith('relation:')) {
  138. return this.name.substr(9);
  139. } else {
  140. return this.name;
  141. }
  142. }
  143. get isDeleted() {
  144. return !(this.attributeId in this.becca.attributes);
  145. }
  146. beforeSaving() {
  147. if (!this.value) {
  148. if (this.type === 'relation') {
  149. throw new Error(`Cannot save relation ${this.name} since it does not target any note.`);
  150. }
  151. // null value isn't allowed
  152. this.value = "";
  153. }
  154. if (this.position === undefined) {
  155. // TODO: can be calculated from becca
  156. this.position = 1 + sql.getValue(`SELECT COALESCE(MAX(position), 0) FROM attributes WHERE noteId = ?`, [this.noteId]);
  157. }
  158. if (!this.isInheritable) {
  159. this.isInheritable = false;
  160. }
  161. this.utcDateModified = dateUtils.utcNowDateTime();
  162. super.beforeSaving();
  163. this.becca.attributes[this.attributeId] = this;
  164. }
  165. getPojo() {
  166. return {
  167. attributeId: this.attributeId,
  168. noteId: this.noteId,
  169. type: this.type,
  170. name: this.name,
  171. position: this.position,
  172. value: this.value,
  173. isInheritable: this.isInheritable,
  174. utcDateModified: this.utcDateModified,
  175. isDeleted: false
  176. };
  177. }
  178. createClone(type, name, value, isInheritable) {
  179. return new Attribute({
  180. noteId: this.noteId,
  181. type: type,
  182. name: name,
  183. value: value,
  184. position: this.position,
  185. isInheritable: isInheritable,
  186. utcDateModified: this.utcDateModified
  187. });
  188. }
  189. }
  190. module.exports = Attribute;
  191. </code></pre>
  192. </article>
  193. </section>
  194. </div>
  195. <nav>
  196. <h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-sql.html">sql</a></li></ul><h3>Classes</h3><ul><li><a href="Attribute.html">Attribute</a></li><li><a href="BackendScriptApi.html">BackendScriptApi</a></li><li><a href="Branch.html">Branch</a></li><li><a href="EtapiToken.html">EtapiToken</a></li><li><a href="Note.html">Note</a></li><li><a href="NoteRevision.html">NoteRevision</a></li><li><a href="Option.html">Option</a></li><li><a href="RecentNote.html">RecentNote</a></li></ul><h3><a href="global.html">Global</a></h3>
  197. </nav>
  198. <br class="clear">
  199. <footer>
  200. Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.7</a>
  201. </footer>
  202. <script> prettyPrint(); </script>
  203. <script src="scripts/linenumber.js"> </script>
  204. </body>
  205. </html>