split out note's content into separate entity, WIP

This commit is contained in:
zadam 2019-02-06 20:19:25 +01:00
parent 8b250ed523
commit 8884177d9f
18 changed files with 417 additions and 213 deletions

View File

@ -16,586 +16,671 @@
<table id="8" parent="2" name="branches"/> <table id="8" parent="2" name="branches"/>
<table id="9" parent="2" name="event_log"/> <table id="9" parent="2" name="event_log"/>
<table id="10" parent="2" name="links"/> <table id="10" parent="2" name="links"/>
<table id="11" parent="2" name="note_revisions"/> <table id="11" parent="2" name="note_contents"/>
<table id="12" parent="2" name="notes"/> <table id="12" parent="2" name="note_revisions"/>
<table id="13" parent="2" name="options"/> <table id="13" parent="2" name="notes"/>
<table id="14" parent="2" name="recent_notes"/> <table id="14" parent="2" name="options"/>
<table id="15" parent="2" name="source_ids"/> <table id="15" parent="2" name="recent_notes"/>
<table id="16" parent="2" name="sqlite_master"> <table id="16" parent="2" name="source_ids"/>
<table id="17" parent="2" name="sqlite_master">
<System>1</System> <System>1</System>
</table> </table>
<table id="17" parent="2" name="sqlite_sequence"> <table id="18" parent="2" name="sqlite_sequence">
<System>1</System> <System>1</System>
</table> </table>
<table id="18" parent="2" name="sync"/> <table id="19" parent="2" name="sync"/>
<column id="19" parent="6" name="apiTokenId"> <column id="20" parent="6" name="apiTokenId">
<Position>1</Position> <Position>1</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="20" parent="6" name="token"> <column id="21" parent="6" name="token">
<Position>2</Position> <Position>2</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="21" parent="6" name="dateCreated"> <column id="22" parent="6" name="dateCreated">
<Position>3</Position> <Position>3</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="22" parent="6" name="isDeleted"> <column id="23" parent="6" name="isDeleted">
<Position>4</Position> <Position>4</Position>
<DataType>INT|0s</DataType> <DataType>INT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
<DefaultExpression>0</DefaultExpression> <DefaultExpression>0</DefaultExpression>
</column> </column>
<column id="23" parent="6" name="hash"> <column id="24" parent="6" name="hash">
<Position>5</Position> <Position>5</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
<DefaultExpression>&quot;&quot;</DefaultExpression> <DefaultExpression>&quot;&quot;</DefaultExpression>
</column> </column>
<index id="24" parent="6" name="sqlite_autoindex_api_tokens_1"> <index id="25" parent="6" name="sqlite_autoindex_api_tokens_1">
<NameSurrogate>1</NameSurrogate> <NameSurrogate>1</NameSurrogate>
<ColNames>apiTokenId</ColNames> <ColNames>apiTokenId</ColNames>
<ColumnCollations></ColumnCollations> <ColumnCollations></ColumnCollations>
<Unique>1</Unique> <Unique>1</Unique>
</index> </index>
<key id="25" parent="6"> <key id="26" parent="6">
<ColNames>apiTokenId</ColNames> <ColNames>apiTokenId</ColNames>
<Primary>1</Primary> <Primary>1</Primary>
<UnderlyingIndexName>sqlite_autoindex_api_tokens_1</UnderlyingIndexName> <UnderlyingIndexName>sqlite_autoindex_api_tokens_1</UnderlyingIndexName>
</key> </key>
<column id="26" parent="7" name="attributeId"> <column id="27" parent="7" name="attributeId">
<Position>1</Position> <Position>1</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="27" parent="7" name="noteId"> <column id="28" parent="7" name="noteId">
<Position>2</Position> <Position>2</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="28" parent="7" name="type"> <column id="29" parent="7" name="type">
<Position>3</Position> <Position>3</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="29" parent="7" name="name"> <column id="30" parent="7" name="name">
<Position>4</Position> <Position>4</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="30" parent="7" name="value"> <column id="31" parent="7" name="value">
<Position>5</Position> <Position>5</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
<DefaultExpression>&apos;&apos;</DefaultExpression> <DefaultExpression>&apos;&apos;</DefaultExpression>
</column> </column>
<column id="31" parent="7" name="position"> <column id="32" parent="7" name="position">
<Position>6</Position> <Position>6</Position>
<DataType>INT|0s</DataType> <DataType>INT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
<DefaultExpression>0</DefaultExpression> <DefaultExpression>0</DefaultExpression>
</column> </column>
<column id="32" parent="7" name="dateCreated"> <column id="33" parent="7" name="dateCreated">
<Position>7</Position> <Position>7</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="33" parent="7" name="dateModified"> <column id="34" parent="7" name="dateModified">
<Position>8</Position> <Position>8</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="34" parent="7" name="isDeleted"> <column id="35" parent="7" name="isDeleted">
<Position>9</Position> <Position>9</Position>
<DataType>INT|0s</DataType> <DataType>INT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="35" parent="7" name="hash"> <column id="36" parent="7" name="hash">
<Position>10</Position> <Position>10</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
<DefaultExpression>&quot;&quot;</DefaultExpression> <DefaultExpression>&quot;&quot;</DefaultExpression>
</column> </column>
<column id="36" parent="7" name="isInheritable"> <column id="37" parent="7" name="isInheritable">
<Position>11</Position> <Position>11</Position>
<DataType>int|0s</DataType> <DataType>int|0s</DataType>
<DefaultExpression>0</DefaultExpression> <DefaultExpression>0</DefaultExpression>
</column> </column>
<index id="37" parent="7" name="sqlite_autoindex_attributes_1"> <index id="38" parent="7" name="sqlite_autoindex_attributes_1">
<NameSurrogate>1</NameSurrogate> <NameSurrogate>1</NameSurrogate>
<ColNames>attributeId</ColNames> <ColNames>attributeId</ColNames>
<ColumnCollations></ColumnCollations> <ColumnCollations></ColumnCollations>
<Unique>1</Unique> <Unique>1</Unique>
</index> </index>
<key id="38" parent="7"> <index id="39" parent="7" name="IDX_attributes_noteId">
<ColNames>noteId</ColNames>
<ColumnCollations></ColumnCollations>
</index>
<index id="40" parent="7" name="IDX_attributes_noteId_index">
<ColNames>noteId</ColNames>
<ColumnCollations></ColumnCollations>
</index>
<index id="41" parent="7" name="IDX_attributes_name_value">
<ColNames>name
value</ColNames>
<ColumnCollations></ColumnCollations>
</index>
<index id="42" parent="7" name="IDX_attributes_name">
<ColNames>name</ColNames>
<ColumnCollations></ColumnCollations>
</index>
<index id="43" parent="7" name="IDX_attributes_name_index">
<ColNames>name</ColNames>
<ColumnCollations></ColumnCollations>
</index>
<index id="44" parent="7" name="IDX_attributes_value">
<ColNames>value</ColNames>
<ColumnCollations></ColumnCollations>
</index>
<index id="45" parent="7" name="IDX_attributes_value_index">
<ColNames>value</ColNames>
<ColumnCollations></ColumnCollations>
</index>
<key id="46" parent="7">
<ColNames>attributeId</ColNames> <ColNames>attributeId</ColNames>
<Primary>1</Primary> <Primary>1</Primary>
<UnderlyingIndexName>sqlite_autoindex_attributes_1</UnderlyingIndexName> <UnderlyingIndexName>sqlite_autoindex_attributes_1</UnderlyingIndexName>
</key> </key>
<column id="39" parent="8" name="branchId"> <column id="47" parent="8" name="branchId">
<Position>1</Position> <Position>1</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="40" parent="8" name="noteId"> <column id="48" parent="8" name="noteId">
<Position>2</Position> <Position>2</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="41" parent="8" name="parentNoteId"> <column id="49" parent="8" name="parentNoteId">
<Position>3</Position> <Position>3</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="42" parent="8" name="notePosition"> <column id="50" parent="8" name="notePosition">
<Position>4</Position> <Position>4</Position>
<DataType>INTEGER|0s</DataType> <DataType>INTEGER|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="43" parent="8" name="prefix"> <column id="51" parent="8" name="prefix">
<Position>5</Position> <Position>5</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
</column> </column>
<column id="44" parent="8" name="isExpanded"> <column id="52" parent="8" name="isExpanded">
<Position>6</Position> <Position>6</Position>
<DataType>BOOLEAN|0s</DataType> <DataType>BOOLEAN|0s</DataType>
</column> </column>
<column id="45" parent="8" name="isDeleted"> <column id="53" parent="8" name="isDeleted">
<Position>7</Position> <Position>7</Position>
<DataType>INTEGER|0s</DataType> <DataType>INTEGER|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
<DefaultExpression>0</DefaultExpression> <DefaultExpression>0</DefaultExpression>
</column> </column>
<column id="46" parent="8" name="dateModified"> <column id="54" parent="8" name="dateModified">
<Position>8</Position> <Position>8</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="47" parent="8" name="hash"> <column id="55" parent="8" name="hash">
<Position>9</Position> <Position>9</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
<DefaultExpression>&quot;&quot;</DefaultExpression> <DefaultExpression>&quot;&quot;</DefaultExpression>
</column> </column>
<column id="48" parent="8" name="dateCreated"> <column id="56" parent="8" name="dateCreated">
<Position>10</Position> <Position>10</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
<DefaultExpression>&apos;1970-01-01T00:00:00.000Z&apos;</DefaultExpression> <DefaultExpression>&apos;1970-01-01T00:00:00.000Z&apos;</DefaultExpression>
</column> </column>
<index id="49" parent="8" name="sqlite_autoindex_branches_1"> <index id="57" parent="8" name="sqlite_autoindex_branches_1">
<NameSurrogate>1</NameSurrogate> <NameSurrogate>1</NameSurrogate>
<ColNames>branchId</ColNames> <ColNames>branchId</ColNames>
<ColumnCollations></ColumnCollations> <ColumnCollations></ColumnCollations>
<Unique>1</Unique> <Unique>1</Unique>
</index> </index>
<index id="50" parent="8" name="IDX_branches_noteId_parentNoteId"> <index id="58" parent="8" name="IDX_branches_noteId_parentNoteId">
<ColNames>noteId <ColNames>noteId
parentNoteId</ColNames> parentNoteId</ColNames>
<ColumnCollations></ColumnCollations> <ColumnCollations></ColumnCollations>
</index> </index>
<index id="51" parent="8" name="IDX_branches_noteId"> <index id="59" parent="8" name="IDX_branches_noteId">
<ColNames>noteId</ColNames> <ColNames>noteId</ColNames>
<ColumnCollations></ColumnCollations> <ColumnCollations></ColumnCollations>
</index> </index>
<index id="52" parent="8" name="IDX_branches_parentNoteId"> <index id="60" parent="8" name="IDX_branches_parentNoteId">
<ColNames>parentNoteId</ColNames> <ColNames>parentNoteId</ColNames>
<ColumnCollations></ColumnCollations> <ColumnCollations></ColumnCollations>
</index> </index>
<key id="53" parent="8"> <key id="61" parent="8">
<ColNames>branchId</ColNames> <ColNames>branchId</ColNames>
<Primary>1</Primary> <Primary>1</Primary>
<UnderlyingIndexName>sqlite_autoindex_branches_1</UnderlyingIndexName> <UnderlyingIndexName>sqlite_autoindex_branches_1</UnderlyingIndexName>
</key> </key>
<column id="54" parent="9" name="eventId"> <column id="62" parent="9" name="eventId">
<Position>1</Position> <Position>1</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="55" parent="9" name="noteId"> <column id="63" parent="9" name="noteId">
<Position>2</Position> <Position>2</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
</column> </column>
<column id="56" parent="9" name="comment"> <column id="64" parent="9" name="comment">
<Position>3</Position> <Position>3</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
</column> </column>
<column id="57" parent="9" name="dateCreated"> <column id="65" parent="9" name="dateCreated">
<Position>4</Position> <Position>4</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<index id="58" parent="9" name="sqlite_autoindex_event_log_1"> <index id="66" parent="9" name="sqlite_autoindex_event_log_1">
<NameSurrogate>1</NameSurrogate> <NameSurrogate>1</NameSurrogate>
<ColNames>eventId</ColNames> <ColNames>eventId</ColNames>
<ColumnCollations></ColumnCollations> <ColumnCollations></ColumnCollations>
<Unique>1</Unique> <Unique>1</Unique>
</index> </index>
<key id="59" parent="9"> <index id="67" parent="9" name="IDX_event_log_noteId">
<ColNames>noteId</ColNames>
<ColumnCollations></ColumnCollations>
</index>
<key id="68" parent="9">
<ColNames>eventId</ColNames> <ColNames>eventId</ColNames>
<Primary>1</Primary> <Primary>1</Primary>
<UnderlyingIndexName>sqlite_autoindex_event_log_1</UnderlyingIndexName> <UnderlyingIndexName>sqlite_autoindex_event_log_1</UnderlyingIndexName>
</key> </key>
<column id="60" parent="10" name="linkId"> <column id="69" parent="10" name="linkId">
<Position>1</Position> <Position>1</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="61" parent="10" name="noteId"> <column id="70" parent="10" name="noteId">
<Position>2</Position> <Position>2</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="62" parent="10" name="targetNoteId"> <column id="71" parent="10" name="targetNoteId">
<Position>3</Position> <Position>3</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="63" parent="10" name="type"> <column id="72" parent="10" name="type">
<Position>4</Position> <Position>4</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="64" parent="10" name="isDeleted"> <column id="73" parent="10" name="hash">
<Position>5</Position> <Position>5</Position>
<DataType>INTEGER|0s</DataType>
<NotNull>1</NotNull>
<DefaultExpression>0</DefaultExpression>
</column>
<column id="65" parent="10" name="dateCreated">
<Position>6</Position>
<DataType>TEXT|0s</DataType>
<NotNull>1</NotNull>
</column>
<column id="66" parent="10" name="dateModified">
<Position>7</Position>
<DataType>TEXT|0s</DataType>
<NotNull>1</NotNull>
</column>
<column id="67" parent="10" name="hash">
<Position>8</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
<DefaultExpression>&quot;&quot;</DefaultExpression> <DefaultExpression>&quot;&quot;</DefaultExpression>
</column> </column>
<index id="68" parent="10" name="sqlite_autoindex_links_1"> <column id="74" parent="10" name="isDeleted">
<Position>6</Position>
<DataType>INTEGER|0s</DataType>
<NotNull>1</NotNull>
<DefaultExpression>0</DefaultExpression>
</column>
<column id="75" parent="10" name="dateCreated">
<Position>7</Position>
<DataType>TEXT|0s</DataType>
<NotNull>1</NotNull>
</column>
<column id="76" parent="10" name="dateModified">
<Position>8</Position>
<DataType>TEXT|0s</DataType>
<NotNull>1</NotNull>
</column>
<index id="77" parent="10" name="sqlite_autoindex_links_1">
<NameSurrogate>1</NameSurrogate> <NameSurrogate>1</NameSurrogate>
<ColNames>linkId</ColNames> <ColNames>linkId</ColNames>
<ColumnCollations></ColumnCollations> <ColumnCollations></ColumnCollations>
<Unique>1</Unique> <Unique>1</Unique>
</index> </index>
<key id="69" parent="10"> <index id="78" parent="10" name="IDX_links_noteId">
<ColNames>noteId</ColNames>
<ColumnCollations></ColumnCollations>
</index>
<index id="79" parent="10" name="IDX_links_noteId_index">
<ColNames>noteId</ColNames>
<ColumnCollations></ColumnCollations>
</index>
<index id="80" parent="10" name="IDX_links_targetNoteId">
<ColNames>targetNoteId</ColNames>
<ColumnCollations></ColumnCollations>
</index>
<index id="81" parent="10" name="IDX_links_targetNoteId_index">
<ColNames>targetNoteId</ColNames>
<ColumnCollations></ColumnCollations>
</index>
<key id="82" parent="10">
<ColNames>linkId</ColNames> <ColNames>linkId</ColNames>
<Primary>1</Primary> <Primary>1</Primary>
<UnderlyingIndexName>sqlite_autoindex_links_1</UnderlyingIndexName> <UnderlyingIndexName>sqlite_autoindex_links_1</UnderlyingIndexName>
</key> </key>
<column id="70" parent="11" name="noteRevisionId"> <column id="83" parent="11" name="noteContentId">
<Position>1</Position> <Position>1</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="71" parent="11" name="noteId"> <column id="84" parent="11" name="noteId">
<Position>2</Position> <Position>2</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="72" parent="11" name="title"> <column id="85" parent="11" name="isProtected">
<Position>3</Position>
<DataType>INT|0s</DataType>
<NotNull>1</NotNull>
<DefaultExpression>0</DefaultExpression>
</column>
<column id="86" parent="11" name="content">
<Position>4</Position>
<DataType>TEXT|0s</DataType>
<DefaultExpression>NULL</DefaultExpression>
</column>
<index id="87" parent="11" name="sqlite_autoindex_note_contents_1">
<NameSurrogate>1</NameSurrogate>
<ColNames>noteContentId</ColNames>
<ColumnCollations></ColumnCollations>
<Unique>1</Unique>
</index>
<index id="88" parent="11" name="IDX_note_contents_noteId">
<ColNames>noteId</ColNames>
<ColumnCollations></ColumnCollations>
</index>
<key id="89" parent="11">
<ColNames>noteContentId</ColNames>
<Primary>1</Primary>
<UnderlyingIndexName>sqlite_autoindex_note_contents_1</UnderlyingIndexName>
</key>
<column id="90" parent="12" name="noteRevisionId">
<Position>1</Position>
<DataType>TEXT|0s</DataType>
<NotNull>1</NotNull>
</column>
<column id="91" parent="12" name="noteId">
<Position>2</Position>
<DataType>TEXT|0s</DataType>
<NotNull>1</NotNull>
</column>
<column id="92" parent="12" name="title">
<Position>3</Position> <Position>3</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
</column> </column>
<column id="73" parent="11" name="content"> <column id="93" parent="12" name="content">
<Position>4</Position> <Position>4</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
</column> </column>
<column id="74" parent="11" name="isProtected"> <column id="94" parent="12" name="isProtected">
<Position>5</Position> <Position>5</Position>
<DataType>INT|0s</DataType> <DataType>INT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
<DefaultExpression>0</DefaultExpression> <DefaultExpression>0</DefaultExpression>
</column> </column>
<column id="75" parent="11" name="dateModifiedFrom"> <column id="95" parent="12" name="dateModifiedFrom">
<Position>6</Position> <Position>6</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="76" parent="11" name="dateModifiedTo"> <column id="96" parent="12" name="dateModifiedTo">
<Position>7</Position> <Position>7</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="77" parent="11" name="type"> <column id="97" parent="12" name="type">
<Position>8</Position> <Position>8</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
<DefaultExpression>&apos;&apos;</DefaultExpression> <DefaultExpression>&apos;&apos;</DefaultExpression>
</column> </column>
<column id="78" parent="11" name="mime"> <column id="98" parent="12" name="mime">
<Position>9</Position> <Position>9</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
<DefaultExpression>&apos;&apos;</DefaultExpression> <DefaultExpression>&apos;&apos;</DefaultExpression>
</column> </column>
<column id="79" parent="11" name="hash"> <column id="99" parent="12" name="hash">
<Position>10</Position> <Position>10</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
<DefaultExpression>&quot;&quot;</DefaultExpression> <DefaultExpression>&quot;&quot;</DefaultExpression>
</column> </column>
<index id="80" parent="11" name="sqlite_autoindex_note_revisions_1"> <index id="100" parent="12" name="sqlite_autoindex_note_revisions_1">
<NameSurrogate>1</NameSurrogate> <NameSurrogate>1</NameSurrogate>
<ColNames>noteRevisionId</ColNames> <ColNames>noteRevisionId</ColNames>
<ColumnCollations></ColumnCollations> <ColumnCollations></ColumnCollations>
<Unique>1</Unique> <Unique>1</Unique>
</index> </index>
<index id="81" parent="11" name="IDX_note_revisions_noteId"> <index id="101" parent="12" name="IDX_note_revisions_noteId">
<ColNames>noteId</ColNames> <ColNames>noteId</ColNames>
<ColumnCollations></ColumnCollations> <ColumnCollations></ColumnCollations>
</index> </index>
<index id="82" parent="11" name="IDX_note_revisions_dateModifiedFrom"> <index id="102" parent="12" name="IDX_note_revisions_dateModifiedFrom">
<ColNames>dateModifiedFrom</ColNames> <ColNames>dateModifiedFrom</ColNames>
<ColumnCollations></ColumnCollations> <ColumnCollations></ColumnCollations>
</index> </index>
<index id="83" parent="11" name="IDX_note_revisions_dateModifiedTo"> <index id="103" parent="12" name="IDX_note_revisions_dateModifiedTo">
<ColNames>dateModifiedTo</ColNames> <ColNames>dateModifiedTo</ColNames>
<ColumnCollations></ColumnCollations> <ColumnCollations></ColumnCollations>
</index> </index>
<key id="84" parent="11"> <key id="104" parent="12">
<ColNames>noteRevisionId</ColNames> <ColNames>noteRevisionId</ColNames>
<Primary>1</Primary> <Primary>1</Primary>
<UnderlyingIndexName>sqlite_autoindex_note_revisions_1</UnderlyingIndexName> <UnderlyingIndexName>sqlite_autoindex_note_revisions_1</UnderlyingIndexName>
</key> </key>
<column id="85" parent="12" name="noteId"> <column id="105" parent="13" name="noteId">
<Position>1</Position> <Position>1</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="86" parent="12" name="title"> <column id="106" parent="13" name="title">
<Position>2</Position> <Position>2</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
<DefaultExpression>&quot;note&quot;</DefaultExpression> <DefaultExpression>&quot;note&quot;</DefaultExpression>
</column> </column>
<column id="87" parent="12" name="content"> <column id="107" parent="13" name="isProtected">
<Position>3</Position> <Position>3</Position>
<DataType>TEXT|0s</DataType>
<DefaultExpression>NULL</DefaultExpression>
</column>
<column id="88" parent="12" name="isProtected">
<Position>4</Position>
<DataType>INT|0s</DataType> <DataType>INT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
<DefaultExpression>0</DefaultExpression> <DefaultExpression>0</DefaultExpression>
</column> </column>
<column id="89" parent="12" name="type"> <column id="108" parent="13" name="type">
<Position>5</Position> <Position>4</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
<DefaultExpression>&apos;text&apos;</DefaultExpression> <DefaultExpression>&apos;text&apos;</DefaultExpression>
</column> </column>
<column id="90" parent="12" name="mime"> <column id="109" parent="13" name="mime">
<Position>6</Position> <Position>5</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
<DefaultExpression>&apos;text/html&apos;</DefaultExpression> <DefaultExpression>&apos;text/html&apos;</DefaultExpression>
</column> </column>
<column id="91" parent="12" name="hash"> <column id="110" parent="13" name="hash">
<Position>7</Position> <Position>6</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
<DefaultExpression>&quot;&quot;</DefaultExpression> <DefaultExpression>&quot;&quot;</DefaultExpression>
</column> </column>
<column id="92" parent="12" name="isDeleted"> <column id="111" parent="13" name="isDeleted">
<Position>8</Position> <Position>7</Position>
<DataType>INT|0s</DataType> <DataType>INT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
<DefaultExpression>0</DefaultExpression> <DefaultExpression>0</DefaultExpression>
</column> </column>
<column id="93" parent="12" name="dateCreated"> <column id="112" parent="13" name="dateCreated">
<Position>8</Position>
<DataType>TEXT|0s</DataType>
<NotNull>1</NotNull>
</column>
<column id="113" parent="13" name="dateModified">
<Position>9</Position> <Position>9</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="94" parent="12" name="dateModified"> <index id="114" parent="13" name="sqlite_autoindex_notes_1">
<Position>10</Position>
<DataType>TEXT|0s</DataType>
<NotNull>1</NotNull>
</column>
<index id="95" parent="12" name="sqlite_autoindex_notes_1">
<NameSurrogate>1</NameSurrogate> <NameSurrogate>1</NameSurrogate>
<ColNames>noteId</ColNames> <ColNames>noteId</ColNames>
<ColumnCollations></ColumnCollations> <ColumnCollations></ColumnCollations>
<Unique>1</Unique> <Unique>1</Unique>
</index> </index>
<key id="96" parent="12"> <index id="115" parent="13" name="IDX_notes_isDeleted">
<ColNames>isDeleted</ColNames>
<ColumnCollations></ColumnCollations>
</index>
<key id="116" parent="13">
<ColNames>noteId</ColNames> <ColNames>noteId</ColNames>
<Primary>1</Primary> <Primary>1</Primary>
<UnderlyingIndexName>sqlite_autoindex_notes_1</UnderlyingIndexName> <UnderlyingIndexName>sqlite_autoindex_notes_1</UnderlyingIndexName>
</key> </key>
<column id="97" parent="13" name="name"> <column id="117" parent="14" name="name">
<Position>1</Position> <Position>1</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="98" parent="13" name="value"> <column id="118" parent="14" name="value">
<Position>2</Position> <Position>2</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
</column> </column>
<column id="99" parent="13" name="dateModified"> <column id="119" parent="14" name="dateModified">
<Position>3</Position> <Position>3</Position>
<DataType>INT|0s</DataType> <DataType>INT|0s</DataType>
</column> </column>
<column id="100" parent="13" name="isSynced"> <column id="120" parent="14" name="isSynced">
<Position>4</Position> <Position>4</Position>
<DataType>INTEGER|0s</DataType> <DataType>INTEGER|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
<DefaultExpression>0</DefaultExpression> <DefaultExpression>0</DefaultExpression>
</column> </column>
<column id="101" parent="13" name="hash"> <column id="121" parent="14" name="hash">
<Position>5</Position> <Position>5</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
<DefaultExpression>&quot;&quot;</DefaultExpression> <DefaultExpression>&quot;&quot;</DefaultExpression>
</column> </column>
<column id="102" parent="13" name="dateCreated"> <column id="122" parent="14" name="dateCreated">
<Position>6</Position> <Position>6</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
<DefaultExpression>&apos;1970-01-01T00:00:00.000Z&apos;</DefaultExpression> <DefaultExpression>&apos;1970-01-01T00:00:00.000Z&apos;</DefaultExpression>
</column> </column>
<index id="103" parent="13" name="sqlite_autoindex_options_1"> <index id="123" parent="14" name="sqlite_autoindex_options_1">
<NameSurrogate>1</NameSurrogate> <NameSurrogate>1</NameSurrogate>
<ColNames>name</ColNames> <ColNames>name</ColNames>
<ColumnCollations></ColumnCollations> <ColumnCollations></ColumnCollations>
<Unique>1</Unique> <Unique>1</Unique>
</index> </index>
<key id="104" parent="13"> <key id="124" parent="14">
<ColNames>name</ColNames> <ColNames>name</ColNames>
<Primary>1</Primary> <Primary>1</Primary>
<UnderlyingIndexName>sqlite_autoindex_options_1</UnderlyingIndexName> <UnderlyingIndexName>sqlite_autoindex_options_1</UnderlyingIndexName>
</key> </key>
<column id="105" parent="14" name="branchId"> <column id="125" parent="15" name="branchId">
<Position>1</Position> <Position>1</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="106" parent="14" name="notePath"> <column id="126" parent="15" name="notePath">
<Position>2</Position> <Position>2</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="107" parent="14" name="hash"> <column id="127" parent="15" name="hash">
<Position>3</Position> <Position>3</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
<DefaultExpression>&quot;&quot;</DefaultExpression> <DefaultExpression>&quot;&quot;</DefaultExpression>
</column> </column>
<column id="108" parent="14" name="dateCreated"> <column id="128" parent="15" name="dateCreated">
<Position>4</Position> <Position>4</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="109" parent="14" name="isDeleted"> <column id="129" parent="15" name="isDeleted">
<Position>5</Position> <Position>5</Position>
<DataType>INT|0s</DataType> <DataType>INT|0s</DataType>
</column> </column>
<index id="110" parent="14" name="sqlite_autoindex_recent_notes_1"> <index id="130" parent="15" name="sqlite_autoindex_recent_notes_1">
<NameSurrogate>1</NameSurrogate> <NameSurrogate>1</NameSurrogate>
<ColNames>branchId</ColNames> <ColNames>branchId</ColNames>
<ColumnCollations></ColumnCollations> <ColumnCollations></ColumnCollations>
<Unique>1</Unique> <Unique>1</Unique>
</index> </index>
<key id="111" parent="14"> <key id="131" parent="15">
<ColNames>branchId</ColNames> <ColNames>branchId</ColNames>
<Primary>1</Primary> <Primary>1</Primary>
<UnderlyingIndexName>sqlite_autoindex_recent_notes_1</UnderlyingIndexName> <UnderlyingIndexName>sqlite_autoindex_recent_notes_1</UnderlyingIndexName>
</key> </key>
<column id="112" parent="15" name="sourceId"> <column id="132" parent="16" name="sourceId">
<Position>1</Position> <Position>1</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="113" parent="15" name="dateCreated"> <column id="133" parent="16" name="dateCreated">
<Position>2</Position> <Position>2</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<index id="114" parent="15" name="sqlite_autoindex_source_ids_1"> <index id="134" parent="16" name="sqlite_autoindex_source_ids_1">
<NameSurrogate>1</NameSurrogate> <NameSurrogate>1</NameSurrogate>
<ColNames>sourceId</ColNames> <ColNames>sourceId</ColNames>
<ColumnCollations></ColumnCollations> <ColumnCollations></ColumnCollations>
<Unique>1</Unique> <Unique>1</Unique>
</index> </index>
<key id="115" parent="15"> <key id="135" parent="16">
<ColNames>sourceId</ColNames> <ColNames>sourceId</ColNames>
<Primary>1</Primary> <Primary>1</Primary>
<UnderlyingIndexName>sqlite_autoindex_source_ids_1</UnderlyingIndexName> <UnderlyingIndexName>sqlite_autoindex_source_ids_1</UnderlyingIndexName>
</key> </key>
<column id="116" parent="16" name="type"> <column id="136" parent="17" name="type">
<Position>1</Position> <Position>1</Position>
<DataType>text|0s</DataType> <DataType>text|0s</DataType>
</column> </column>
<column id="117" parent="16" name="name"> <column id="137" parent="17" name="name">
<Position>2</Position> <Position>2</Position>
<DataType>text|0s</DataType> <DataType>text|0s</DataType>
</column> </column>
<column id="118" parent="16" name="tbl_name"> <column id="138" parent="17" name="tbl_name">
<Position>3</Position> <Position>3</Position>
<DataType>text|0s</DataType> <DataType>text|0s</DataType>
</column> </column>
<column id="119" parent="16" name="rootpage"> <column id="139" parent="17" name="rootpage">
<Position>4</Position> <Position>4</Position>
<DataType>integer|0s</DataType> <DataType>integer|0s</DataType>
</column> </column>
<column id="120" parent="16" name="sql"> <column id="140" parent="17" name="sql">
<Position>5</Position> <Position>5</Position>
<DataType>text|0s</DataType> <DataType>text|0s</DataType>
</column> </column>
<column id="121" parent="17" name="name"> <column id="141" parent="18" name="name">
<Position>1</Position> <Position>1</Position>
</column> </column>
<column id="122" parent="17" name="seq"> <column id="142" parent="18" name="seq">
<Position>2</Position> <Position>2</Position>
</column> </column>
<column id="123" parent="18" name="id"> <column id="143" parent="19" name="id">
<Position>1</Position> <Position>1</Position>
<DataType>INTEGER|0s</DataType> <DataType>INTEGER|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
<SequenceIdentity>1</SequenceIdentity> <SequenceIdentity>1</SequenceIdentity>
</column> </column>
<column id="124" parent="18" name="entityName"> <column id="144" parent="19" name="entityName">
<Position>2</Position> <Position>2</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="125" parent="18" name="entityId"> <column id="145" parent="19" name="entityId">
<Position>3</Position> <Position>3</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="126" parent="18" name="sourceId"> <column id="146" parent="19" name="sourceId">
<Position>4</Position> <Position>4</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<column id="127" parent="18" name="syncDate"> <column id="147" parent="19" name="syncDate">
<Position>5</Position> <Position>5</Position>
<DataType>TEXT|0s</DataType> <DataType>TEXT|0s</DataType>
<NotNull>1</NotNull> <NotNull>1</NotNull>
</column> </column>
<index id="128" parent="18" name="IDX_sync_entityName_entityId"> <index id="148" parent="19" name="IDX_sync_entityName_entityId">
<ColNames>entityName <ColNames>entityName
entityId</ColNames> entityId</ColNames>
<ColumnCollations></ColumnCollations> <ColumnCollations></ColumnCollations>
<Unique>1</Unique> <Unique>1</Unique>
</index> </index>
<index id="129" parent="18" name="IDX_sync_syncDate"> <index id="149" parent="19" name="IDX_sync_syncDate">
<ColNames>syncDate</ColNames> <ColNames>syncDate</ColNames>
<ColumnCollations></ColumnCollations> <ColumnCollations></ColumnCollations>
</index> </index>
<key id="130" parent="18"> <key id="150" parent="19">
<ColNames>id</ColNames> <ColNames>id</ColNames>
<Primary>1</Primary> <Primary>1</Primary>
</key> </key>

View File

@ -0,0 +1,34 @@
CREATE TABLE IF NOT EXISTS "note_contents" (
`noteContentId` TEXT NOT NULL,
`noteId` TEXT NOT NULL,
`isProtected` INT NOT NULL DEFAULT 0,
`content` TEXT NULL DEFAULT NULL,
PRIMARY KEY(`noteContentId`)
);
CREATE UNIQUE INDEX `IDX_note_contents_noteId` ON `note_contents` (`noteId`);
INSERT INTO note_contents (noteContentId, noteId, isProtected, content)
SELECT 'C' || SUBSTR(noteId, 2), noteId, isProtected, content FROM notes;
CREATE TABLE IF NOT EXISTS "notes_mig" (
`noteId` TEXT NOT NULL,
`title` TEXT NOT NULL DEFAULT "note",
`isProtected` INT NOT NULL DEFAULT 0,
`type` TEXT NOT NULL DEFAULT 'text',
`mime` TEXT NOT NULL DEFAULT 'text/html',
`hash` TEXT DEFAULT "" NOT NULL,
`isDeleted` INT NOT NULL DEFAULT 0,
`dateCreated` TEXT NOT NULL,
`dateModified` TEXT NOT NULL,
PRIMARY KEY(`noteId`)
);
INSERT INTO notes_mig (noteId, title, isProtected, isDeleted, dateCreated, dateModified, type, mime, hash)
SELECT noteId, title, isProtected, isDeleted, dateCreated, dateModified, type, mime, hash FROM notes;
DROP TABLE notes;
ALTER TABLE notes_mig RENAME TO notes;
CREATE INDEX `IDX_notes_isDeleted` ON `notes` (`isDeleted`);

View File

@ -0,0 +1,8 @@
CREATE INDEX `IDX_attributes_noteId` ON `attributes` (`noteId`);
CREATE INDEX `IDX_attributes_name` ON `attributes` (`name`);
CREATE INDEX `IDX_attributes_value` ON `attributes` (`value`);
CREATE INDEX `IDX_event_log_noteId` ON `event_log` (`noteId`);
CREATE INDEX `IDX_links_noteId` ON `links` (`noteId`);
CREATE INDEX `IDX_links_targetNoteId` ON `links` (`targetNoteId`);

View File

@ -1,4 +1,5 @@
const Note = require('../entities/note'); const Note = require('../entities/note');
const NoteContent = require('../entities/note_content');
const NoteRevision = require('../entities/note_revision'); const NoteRevision = require('../entities/note_revision');
const Link = require('../entities/link'); const Link = require('../entities/link');
const Branch = require('../entities/branch'); const Branch = require('../entities/branch');
@ -12,6 +13,7 @@ const ENTITY_NAME_TO_ENTITY = {
"attributes": Attribute, "attributes": Attribute,
"branches": Branch, "branches": Branch,
"notes": Note, "notes": Note,
"note_contents": NoteContent,
"note_revisions": NoteRevision, "note_revisions": NoteRevision,
"recent_notes": RecentNote, "recent_notes": RecentNote,
"options": Option, "options": Option,
@ -48,6 +50,9 @@ function createEntityFromRow(row) {
else if (row.branchId) { else if (row.branchId) {
entity = new Branch(row); entity = new Branch(row);
} }
else if (row.noteContentId) {
entity = new NoteContent(row);
}
else if (row.noteId) { else if (row.noteId) {
entity = new Note(row); entity = new Note(row);
} }

View File

@ -19,7 +19,6 @@ const RELATION_DEFINITION = 'relation-definition';
* @property {string} type - one of "text", "code", "file" or "render" * @property {string} type - one of "text", "code", "file" or "render"
* @property {string} mime - MIME type, e.g. "text/html" * @property {string} mime - MIME type, e.g. "text/html"
* @property {string} title - note title * @property {string} title - note title
* @property {string} content - note content - e.g. HTML text for text notes, file payload for files
* @property {boolean} isProtected - true if note is protected * @property {boolean} isProtected - true if note is protected
* @property {boolean} isDeleted - true if note is deleted * @property {boolean} isDeleted - true if note is deleted
* @property {string} dateCreated * @property {string} dateCreated
@ -30,7 +29,7 @@ const RELATION_DEFINITION = 'relation-definition';
class Note extends Entity { class Note extends Entity {
static get entityName() { return "notes"; } static get entityName() { return "notes"; }
static get primaryKeyName() { return "noteId"; } static get primaryKeyName() { return "noteId"; }
static get hashedProperties() { return ["noteId", "title", "content", "type", "isProtected", "isDeleted"]; } static get hashedProperties() { return ["noteId", "title", "type", "isProtected", "isDeleted"]; }
/** /**
* @param row - object containing database row from "notes" table * @param row - object containing database row from "notes" table
@ -54,26 +53,18 @@ class Note extends Entity {
// saving ciphertexts in case we do want to update protected note outside of protected session // saving ciphertexts in case we do want to update protected note outside of protected session
// (which is allowed) // (which is allowed)
this.titleCipherText = this.title; this.titleCipherText = this.title;
this.contentCipherText = this.content;
this.title = "[protected]"; this.title = "[protected]";
this.content = ""; }
} }
} }
this.setContent(this.content); /** @returns {Promise<NoteContent>} */
async getNoteContent() {
if (!this.noteContent) {
this.noteContent = await repository.getEntity(`SELECT * FROM note_contents WHERE noteId = ?`, [this.noteId]);
} }
setContent(content) { return this.noteContent;
this.content = content;
// if parsing below is not successful then there's no jsonContent as opposed to still having the old unupdated ones
delete this.jsonContent;
try {
this.jsonContent = JSON.parse(this.content);
}
catch(e) {}
} }
/** @returns {boolean} true if this note is the root of the note tree. Root note has "root" noteId */ /** @returns {boolean} true if this note is the root of the note tree. Root note has "root" noteId */

View File

@ -0,0 +1,82 @@
"use strict";
const Entity = require('./entity');
const protectedSessionService = require('../services/protected_session');
const repository = require('../services/repository');
/**
* This represents a Note which is a central object in the Trilium Notes project.
*
* @property {string} noteContentId - primary key
* @property {string} noteId - reference to owning note
* @property {boolean} isProtected - true if note content is protected
* @property {blob} content - note content - e.g. HTML text for text notes, file payload for files
*
* @extends Entity
*/
class NoteContent extends Entity {
static get entityName() {
return "note_contents";
}
static get primaryKeyName() {
return "noteContentId";
}
static get hashedProperties() {
return ["noteContentId", "noteId", "isProtected", "content"];
}
/**
* @param row - object containing database row from "note_contents" table
*/
constructor(row) {
super(row);
this.isProtected = !!this.isProtected;
/* true if content (meaning any kind of potentially encrypted content) is either not encrypted
* or encrypted, but with available protected session (so effectively decrypted) */
this.isContentAvailable = true;
// check if there's noteContentId, otherwise this is a new entity which wasn't encrypted yet
if (this.isProtected && this.noteContentId) {
this.isContentAvailable = protectedSessionService.isProtectedSessionAvailable();
if (this.isContentAvailable) {
protectedSessionService.decryptNoteContent(this);
}
else {
// saving ciphertexts in case we do want to update protected note outside of protected session
// (which is allowed)
this.contentCipherText = this.content;
this.content = "";
}
}
}
/**
* @returns {Promise<Note>}
*/
async getNote() {
return await repository.getNote(this.noteId);
}
// cannot be static!
updatePojo(pojo) {
if (pojo.isProtected) {
if (this.isContentAvailable) {
protectedSessionService.encryptNoteContent(pojo);
}
else {
// updating protected note outside of protected session means we will keep original ciphertext
pojo.content = pojo.contentCipherText;
}
}
delete pojo.jsonContent;
delete pojo.isContentAvailable;
delete pojo.contentCipherText;
}
}
module.exports = NoteContent;

View File

@ -8,15 +8,15 @@ class NoteFull extends NoteShort {
super(treeCache, row); super(treeCache, row);
/** @param {string} */ /** @param {string} */
this.content = row.content; this.noteContent = row.noteContent;
if (this.content !== "" && this.isJson()) { // if (this.content !== "" && this.isJson()) {
try { // try {
/** @param {object} */ // /** @param {object} */
this.jsonContent = JSON.parse(this.content); // this.jsonContent = JSON.parse(this.content);
} // }
catch(e) {} // catch(e) {}
} // }
} }
} }

View File

@ -357,6 +357,7 @@ export default {
updateNoteView, updateNoteView,
loadNote, loadNote,
getCurrentNote, getCurrentNote,
getCurrentNoteContent,
getCurrentNoteType, getCurrentNoteType,
getCurrentNoteId, getCurrentNoteId,
focusOnTitle, focusOnTitle,
@ -364,7 +365,6 @@ export default {
saveNote, saveNote,
saveNoteIfChanged, saveNoteIfChanged,
noteChanged, noteChanged,
getCurrentNoteContent,
onNoteChange, onNoteChange,
addDetailLoadedListener addDetailLoadedListener
}; };

View File

@ -49,7 +49,7 @@ async function show() {
// this needs to happen after the element is shown, otherwise the editor won't be refreshed // this needs to happen after the element is shown, otherwise the editor won't be refreshed
// CodeMirror breaks pretty badly on null so even though it shouldn't happen (guarded by consistency check) // CodeMirror breaks pretty badly on null so even though it shouldn't happen (guarded by consistency check)
// we provide fallback // we provide fallback
codeEditor.setValue(currentNote.content || ""); codeEditor.setValue(currentNote.noteContent.content || "");
const info = CodeMirror.findModeByMIME(currentNote.mime); const info = CodeMirror.findModeByMIME(currentNote.mime);

View File

@ -27,8 +27,8 @@ async function show() {
$fileSize.text((attributeMap.fileSize || "?") + " bytes"); $fileSize.text((attributeMap.fileSize || "?") + " bytes");
$fileType.text(currentNote.mime); $fileType.text(currentNote.mime);
$previewRow.toggle(!!currentNote.content); $previewRow.toggle(!!currentNote.noteContent.content);
$previewContent.text(currentNote.content); $previewContent.text(currentNote.noteContent.content);
} }
$downloadButton.click(() => utils.download(getFileUrl())); $downloadButton.click(() => utils.download(getFileUrl()));

View File

@ -93,9 +93,9 @@ function loadMapData() {
} }
}; };
if (currentNote.content) { if (currentNote.noteContent.content) {
try { try {
mapData = JSON.parse(currentNote.content); mapData = JSON.parse(currentNote.noteContent.content);
} catch (e) { } catch (e) {
console.log("Could not parse content: ", e); console.log("Could not parse content: ", e);
} }

View File

@ -16,7 +16,7 @@ function show() {
$component.show(); $component.show();
try { try {
const json = JSON.parse(noteDetailService.getCurrentNote().content); const json = JSON.parse(noteDetailService.getCurrentNote().noteContent.content);
$searchString.val(json.searchString); $searchString.val(json.searchString);
} }

View File

@ -22,7 +22,7 @@ async function show() {
textEditor.isReadOnly = await isReadOnly(); textEditor.isReadOnly = await isReadOnly();
textEditor.setData(noteDetailService.getCurrentNote().content); textEditor.setData(noteDetailService.getCurrentNote().noteContent.content);
$component.show(); $component.show();
} }

View File

@ -12,18 +12,10 @@ async function getNote(req) {
return [404, "Note " + noteId + " has not been found."]; return [404, "Note " + noteId + " has not been found."];
} }
if (note.type === 'file' || note.type === 'image') { if (note.mime.startsWith('text/')) {
if (note.type === 'file' && note.mime.startsWith('text/')) { const noteContent = await note.getNoteContent();
note.content = note.content.toString("UTF-8");
if (note.content.length > 10000) { noteContent.content = noteContent.content.toString("UTF-8");
note.content = note.content.substr(0, 10000) + "...";
}
}
else {
// no need to transfer (potentially large) file/image payload for this request
note.content = null;
}
} }
return note; return note;

View File

@ -4,8 +4,8 @@ const build = require('./build');
const packageJson = require('../../package'); const packageJson = require('../../package');
const {TRILIUM_DATA_DIR} = require('./data_dir'); const {TRILIUM_DATA_DIR} = require('./data_dir');
const APP_DB_VERSION = 124; const APP_DB_VERSION = 125;
const SYNC_VERSION = 4; const SYNC_VERSION = 5;
module.exports = { module.exports = {
appVersion: packageJson.version, appVersion: packageJson.version,

View File

@ -234,6 +234,7 @@ async function findLogicIssues() {
await findIssues(` await findIssues(`
SELECT noteId SELECT noteId
FROM notes FROM notes
JOIN note_contents USING(noteId)
WHERE WHERE
isDeleted = 0 isDeleted = 0
AND content IS NULL`, AND content IS NULL`,

View File

@ -47,28 +47,25 @@ function decryptNoteTitle(noteId, encryptedTitle) {
} }
function decryptNote(note) { function decryptNote(note) {
const dataKey = getDataKey();
if (!note.isProtected) { if (!note.isProtected) {
return; return;
} }
try {
if (note.title) { if (note.title) {
note.title = dataEncryptionService.decryptString(dataKey, note.title); note.title = decryptNoteTitle(note.noteId)
}
} }
if (note.content) { function decryptNoteContent(noteContent) {
if (note.type === 'file' || note.type === 'image') { if (!noteContent.isProtected) {
note.content = dataEncryptionService.decrypt(dataKey, note.content); return;
}
else {
note.content = dataEncryptionService.decryptString(dataKey, note.content);
}
} }
try {
noteContent.content = dataEncryptionService.decrypt(getDataKey(), noteContent.content);
} }
catch (e) { catch (e) {
e.message = `Cannot decrypt note for noteId=${note.noteId}: ` + e.message; e.message = `Cannot decrypt note content for noteContentId=${noteContent.noteContentId}: ` + e.message;
throw e; throw e;
} }
} }
@ -96,10 +93,11 @@ function decryptNoteRevision(hist) {
} }
function encryptNote(note) { function encryptNote(note) {
const dataKey = getDataKey(); note.title = dataEncryptionService.encrypt(getDataKey(), note.title);
}
note.title = dataEncryptionService.encrypt(dataKey, note.title); function encryptNoteContent(noteContent) {
note.content = dataEncryptionService.encrypt(dataKey, note.content); noteContent.content = dataEncryptionService.encrypt(getDataKey(), noteContent.content);
} }
function encryptNoteRevision(revision) { function encryptNoteRevision(revision) {
@ -115,9 +113,11 @@ module.exports = {
isProtectedSessionAvailable, isProtectedSessionAvailable,
decryptNoteTitle, decryptNoteTitle,
decryptNote, decryptNote,
decryptNoteContent,
decryptNotes, decryptNotes,
decryptNoteRevision, decryptNoteRevision,
encryptNote, encryptNote,
encryptNoteContent,
encryptNoteRevision, encryptNoteRevision,
setProtectedSessionId setProtectedSessionId
}; };

View File

@ -37,27 +37,32 @@ async function getEntity(query, params = []) {
return entityConstructor.createEntityFromRow(row); return entityConstructor.createEntityFromRow(row);
} }
/** @returns {Note|null} */ /** @returns {Promise<Note|null>} */
async function getNote(noteId) { async function getNote(noteId) {
return await getEntity("SELECT * FROM notes WHERE noteId = ?", [noteId]); return await getEntity("SELECT * FROM notes WHERE noteId = ?", [noteId]);
} }
/** @returns {Branch|null} */ /** @returns {Promise<NoteContent|null>} */
async function getNoteContent(noteContentId) {
return await getEntity("SELECT * FROM note_contents WHERE noteContentId = ?", [noteContentId]);
}
/** @returns {Promise<Branch|null>} */
async function getBranch(branchId) { async function getBranch(branchId) {
return await getEntity("SELECT * FROM branches WHERE branchId = ?", [branchId]); return await getEntity("SELECT * FROM branches WHERE branchId = ?", [branchId]);
} }
/** @returns {Attribute|null} */ /** @returns {Promise<Attribute|null>} */
async function getAttribute(attributeId) { async function getAttribute(attributeId) {
return await getEntity("SELECT * FROM attributes WHERE attributeId = ?", [attributeId]); return await getEntity("SELECT * FROM attributes WHERE attributeId = ?", [attributeId]);
} }
/** @returns {Option|null} */ /** @returns {Promise<Option|null>} */
async function getOption(name) { async function getOption(name) {
return await getEntity("SELECT * FROM options WHERE name = ?", [name]); return await getEntity("SELECT * FROM options WHERE name = ?", [name]);
} }
/** @returns {Link|null} */ /** @returns {Promise<Link|null>} */
async function getLink(linkId) { async function getLink(linkId) {
return await getEntity("SELECT * FROM links WHERE linkId = ?", [linkId]); return await getEntity("SELECT * FROM links WHERE linkId = ?", [linkId]);
} }
@ -121,6 +126,7 @@ module.exports = {
getEntities, getEntities,
getEntity, getEntity,
getNote, getNote,
getNoteContent,
getBranch, getBranch,
getAttribute, getAttribute,
getOption, getOption,