Skip to content

Commit

Permalink
Only index tags + values if the record is latestBaseState (#725)
Browse files Browse the repository at this point in the history
  • Loading branch information
LiranCohen committed Apr 24, 2024
1 parent 4bdd0c6 commit 0cffa98
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 1 deletion.
3 changes: 2 additions & 1 deletion src/interfaces/records-write.ts
Expand Up @@ -781,7 +781,8 @@ export class RecordsWrite implements MessageInterface<RecordsWriteMessage> {

// in order to avoid name clashes with first-class index keys
// we build the indexes with `tag.property_name` for each tag property.
if (tags !== undefined) {
// we only index tags if the message is the latest base state, as that's the only time filtering for tags is relevant.
if (tags !== undefined && isLatestBaseState === true) {
const flattenedTags = Records.buildTagIndexes({ ...tags });
indexes = { ...indexes, ...flattenedTags };
}
Expand Down
70 changes: 70 additions & 0 deletions tests/features/records-tags.spec.ts
Expand Up @@ -11,7 +11,9 @@ import { DidKey } from '@web5/dids';
import { Dwn } from '../../src/dwn.js';
import { DwnErrorCode } from '../../src/core/dwn-error.js';
import { Jws } from '../../src/utils/jws.js';
import { Records } from '../../src/utils/records.js';
import { RecordsRead } from '../../src/interfaces/records-read.js';
import { RecordsWrite } from '../../src/interfaces/records-write.js';
import { TestDataGenerator } from '../utils/test-data-generator.js';
import { TestEventStream } from '../test-event-stream.js';
import { TestStores } from '../test-stores.js';
Expand Down Expand Up @@ -2117,6 +2119,21 @@ export function testRecordsTags(): void {
numberArrayTag : [ 0, 1 ,2 ],
});

// Sanity: Query for a tag value
const tagsQueryMatch = await TestDataGenerator.generateRecordsQuery({
author : alice,
filter : {
tags: {
stringTag: 'string-value'
}
}
});

const tagsQueryMatchReply = await dwn.processMessage(alice.did, tagsQueryMatch.message);
expect(tagsQueryMatchReply.status.code).to.equal(200);
expect(tagsQueryMatchReply.entries?.length).to.equal(1);
expect(tagsQueryMatchReply.entries![0].recordId).to.equal(tagsRecord1.message.recordId);

// update the record with new tags
const updatedRecord = await TestDataGenerator.generateFromRecordsWrite({
author : alice,
Expand All @@ -2130,6 +2147,59 @@ export function testRecordsTags(): void {
expect(updatedRecordReadReply.status.code).to.equal(200);
expect(updatedRecordReadReply.record).to.not.be.undefined;
expect(updatedRecordReadReply.record!.descriptor.tags).to.deep.equal({ newTag: 'new-value' });

// Sanity: Query for the old tag value should return no results
const tagsQueryMatchReply2 = await dwn.processMessage(alice.did, tagsQueryMatch.message);
expect(tagsQueryMatchReply2.status.code).to.equal(200);
expect(tagsQueryMatchReply2.entries?.length).to.equal(0);
});

it('should not index tags when the record is not `latestBaseState`', async () => {
const buildTagIndexSpy = sinon.spy(Records, 'buildTagIndexes');
const constructIndexesSpy = sinon.spy(RecordsWrite.prototype, 'constructIndexes');

const alice = await TestDataGenerator.generateDidKeyPersona();

// write a record with tags, this should trigger the `buildTagIndexes` method
const tagsRecord1 = await TestDataGenerator.generateRecordsWrite({
author : alice,
published : true,
schema : 'post',
tags : {
stringTag : 'string-value',
numberTag : 54566975,
booleanTag : false,
stringArrayTag : [ 'string-value', 'string-value2' ],
numberArrayTag : [ 0, 1 ,2 ],
}
});

// write the record
const tagsRecord1Reply = await dwn.processMessage(alice.did, tagsRecord1.message, { dataStream: tagsRecord1.dataStream });
expect(tagsRecord1Reply.status.code).to.equal(202);

// verify that construct Indexes was called
expect(constructIndexesSpy.callCount).to.equal(1);
// verify that buildTagIndexes was called
expect(buildTagIndexSpy.callCount).to.equal(1);


// reset counters
constructIndexesSpy.resetHistory();
buildTagIndexSpy.resetHistory();

// update the record without any tags this time
const updatedRecord = await TestDataGenerator.generateFromRecordsWrite({
author : alice,
existingWrite : tagsRecord1.recordsWrite,
});
const updatedRecordReply = await dwn.processMessage(alice.did, updatedRecord.message, { dataStream: updatedRecord.dataStream });
expect(updatedRecordReply.status.code).to.equal(202);

// construct Indexes should be called once for the `initialWrite` and once for the updated write
expect(constructIndexesSpy.callCount).to.equal(2);
// verify that buildTagIndexes was not called at all
expect(buildTagIndexSpy.callCount).to.equal(0);
});
});

Expand Down

0 comments on commit 0cffa98

Please sign in to comment.