From 405fecefa634f5a6fb4e0a5edcc9f60391187606 Mon Sep 17 00:00:00 2001 From: 0xjagger <194556652+0xJagger@users.noreply.github.com> Date: Fri, 23 Jan 2026 12:01:43 -0300 Subject: [PATCH 1/6] refactor(ranks): rename rank-related types and functions to use 'ranking' terminology --- src/ranks/create-rank.ts | 64 ++++++++++++++++++++-------------------- src/ranks/types.ts | 10 +++---- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/ranks/create-rank.ts b/src/ranks/create-rank.ts index 3cce827..5168f9f 100644 --- a/src/ranks/create-rank.ts +++ b/src/ranks/create-rank.ts @@ -18,24 +18,24 @@ import { } from '../core/ids/system.js'; import { Id } from '../id.js'; import { assertValid, generate, toGrcId } from '../id-utils.js'; -import type { CreateRankParams, CreateRankResult, VoteWeighted } from './types.js'; +import type { CreateRankingParams, CreateRankingResult, VoteWeighted } from './types.js'; /** - * Creates a rank entity with the given name, description, rankType, and votes. + * Creates a ranking entity with the given name, description, rankingType, and votes. * All IDs passed to this function are validated. If any invalid ID is provided, * the function will throw an error. * - * For ORDINAL ranks, the position is derived from the array order and fractional + * For ORDINAL rankings, the position is derived from the array order and fractional * indexing strings are generated internally. * * @example * ```ts - * // Create an ordinal rank (ordered list) - position derived from array order - * const { id, ops, voteIds } = createRank({ - * id: rankId, // optional, will be generated if not provided + * // Create an ordinal ranking (ordered list) - position derived from array order + * const { id, ops, voteIds } = createRanking({ + * id: rankingId, // optional, will be generated if not provided * name: 'My Favorite Movies', * description: 'A ranked list of my favorite movies', // optional - * rankType: 'ORDINAL', + * rankingType: 'ORDINAL', * votes: [ * { entityId: movie1Id }, // 1st place * { entityId: movie2Id }, // 2nd place @@ -43,35 +43,35 @@ import type { CreateRankParams, CreateRankResult, VoteWeighted } from './types.j * ], * }); * - * // Create a weighted rank (scored list) - * const { id, ops, voteIds } = createRank({ + * // Create a weighted ranking (scored list) + * const { id, ops, voteIds } = createRanking({ * name: 'Restaurant Ratings', - * rankType: 'WEIGHTED', + * rankingType: 'WEIGHTED', * votes: [ - * { entityId: restaurant1Id, value: 4.5 }, // numeric score - * { entityId: restaurant2Id, value: 3.8 }, + * { entityId: restaurant1Id, score: 4.5 }, // numeric score + * { entityId: restaurant2Id, score: 3.8 }, * ], * }); * ``` * - * @param params – {@link CreateRankParams} - * @returns – {@link CreateRankResult} + * @param params – {@link CreateRankingParams} + * @returns – {@link CreateRankingResult} * @throws Will throw an error if any provided ID is invalid * @throws Will throw an error if any entityId is duplicated in votes */ -export const createRank = ({ +export const createRanking = ({ id: providedId, name, description, - rankType, + rankingType, votes, -}: CreateRankParams): CreateRankResult => { +}: CreateRankingParams): CreateRankingResult => { // Validate all input IDs if (providedId) { - assertValid(providedId, '`id` in `createRank`'); + assertValid(providedId, '`id` in `createRanking`'); } for (const vote of votes) { - assertValid(vote.entityId, '`entityId` in `votes` in `createRank`'); + assertValid(vote.entityId, '`entityId` in `votes` in `createRanking`'); } // Validate no duplicate entity IDs in votes @@ -79,7 +79,7 @@ export const createRank = ({ for (const vote of votes) { const entityId = String(vote.entityId); if (seenEntityIds.has(entityId)) { - throw new Error(`Duplicate entityId in votes: "${entityId}". Each entity can only be voted once per rank.`); + throw new Error(`Duplicate entityId in votes: "${entityId}". Each entity can only be voted once per ranking.`); } seenEntityIds.add(entityId); } @@ -88,8 +88,8 @@ export const createRank = ({ const ops: Op[] = []; const voteIds: Id[] = []; - // Create rank entity values - const rankValues: GrcPropertyValue[] = [ + // Create ranking entity values + const rankingValues: GrcPropertyValue[] = [ { property: toGrcId(NAME_PROPERTY), value: { @@ -102,14 +102,14 @@ export const createRank = ({ property: toGrcId(RANK_TYPE_PROPERTY), value: { type: 'text', - value: rankType, + value: rankingType, language: languages.english(), }, }, ]; if (description) { - rankValues.push({ + rankingValues.push({ property: toGrcId(DESCRIPTION_PROPERTY), value: { type: 'text', @@ -119,15 +119,15 @@ export const createRank = ({ }); } - // Create createEntity op for the rank + // Create createEntity op for the ranking ops.push( grcCreateEntity({ id: toGrcId(id), - values: rankValues, + values: rankingValues, }), ); - // Create relation linking rank to RANK_TYPE (type relation) + // Create relation linking ranking to RANK_TYPE (type relation) ops.push( grcCreateRelation({ id: toGrcId(generate()), @@ -138,8 +138,8 @@ export const createRank = ({ }), ); - // Generate fractional indices for ordinal ranks - const fractionalIndices = rankType === 'ORDINAL' ? generateNJitteredKeysBetween(null, null, votes.length) : []; + // Generate fractional indices for ordinal rankings + const fractionalIndices = rankingType === 'ORDINAL' ? generateNJitteredKeysBetween(null, null, votes.length) : []; // Create votes votes.forEach((vote, i) => { @@ -148,7 +148,7 @@ export const createRank = ({ voteIds.push(voteEntityId); - // Create relation from rank to voted entity + // Create relation from ranking to voted entity ops.push( grcCreateRelation({ id: toGrcId(relationId), @@ -161,7 +161,7 @@ export const createRank = ({ // Create vote entity with the appropriate value property const voteValue: GrcPropertyValue = - rankType === 'ORDINAL' + rankingType === 'ORDINAL' ? { property: toGrcId(VOTE_ORDINAL_VALUE_PROPERTY), value: { @@ -174,7 +174,7 @@ export const createRank = ({ property: toGrcId(VOTE_WEIGHTED_VALUE_PROPERTY), value: { type: 'float64', - value: (vote as VoteWeighted).value, + value: (vote as VoteWeighted).score, }, }; diff --git a/src/ranks/types.ts b/src/ranks/types.ts index ca34711..c98c35b 100644 --- a/src/ranks/types.ts +++ b/src/ranks/types.ts @@ -1,7 +1,7 @@ import type { Id } from '../id.js'; import type { CreateResult } from '../types.js'; -export type RankType = 'ORDINAL' | 'WEIGHTED'; +export type RankingType = 'ORDINAL' | 'WEIGHTED'; /** * Vote with ordinal positioning. @@ -17,19 +17,19 @@ export type VoteOrdinal = { */ export type VoteWeighted = { entityId: Id | string; - value: number; + score: number; }; export type Vote = VoteOrdinal | VoteWeighted; -export type CreateRankParams = { +export type CreateRankingParams = { id?: Id | string; name: string; description?: string; - rankType: RankType; + rankingType: RankingType; votes: Vote[]; }; -export type CreateRankResult = CreateResult & { +export type CreateRankingResult = CreateResult & { voteIds: Id[]; // IDs of created vote entities for reference }; From c1ab2e627f20c30f7fce05f5b270452a6dd843a2 Mon Sep 17 00:00:00 2001 From: 0xjagger <194556652+0xJagger@users.noreply.github.com> Date: Fri, 23 Jan 2026 12:01:58 -0300 Subject: [PATCH 2/6] refactor(ranks): update tests to reflect 'ranking' terminology and adjust related logic --- src/ranks/create-rank.test.ts | 268 +++++++++++++++++----------------- 1 file changed, 134 insertions(+), 134 deletions(-) diff --git a/src/ranks/create-rank.test.ts b/src/ranks/create-rank.test.ts index 01d513f..5983917 100644 --- a/src/ranks/create-rank.test.ts +++ b/src/ranks/create-rank.test.ts @@ -12,36 +12,36 @@ import { } from '../core/ids/system.js'; import { Id, isValid } from '../id.js'; import { toGrcId } from '../id-utils.js'; -import { createRank } from './create-rank.js'; +import { createRanking } from './create-rank.js'; -describe('createRank', () => { +describe('createRanking', () => { const movie1Id = Id('f47ac10b-58cc-4372-a567-0e02b2c3d479'); const movie2Id = Id('550e8400-e29b-41d4-a716-446655440000'); const movie3Id = Id('6ba7b810-9dad-11d1-80b4-00c04fd430c8'); - describe('ordinal ranks', () => { - it('creates a basic ordinal rank with one vote', () => { - const rank = createRank({ + describe('ordinal rankings', () => { + it('creates a basic ordinal ranking with one vote', () => { + const ranking = createRanking({ name: 'My Favorite Movie', - rankType: 'ORDINAL', + rankingType: 'ORDINAL', votes: [{ entityId: movie1Id }], }); - expect(rank).toBeDefined(); - expect(typeof rank.id).toBe('string'); - expect(rank.ops).toBeDefined(); - expect(rank.voteIds).toHaveLength(1); + expect(ranking).toBeDefined(); + expect(typeof ranking.id).toBe('string'); + expect(ranking.ops).toBeDefined(); + expect(ranking.voteIds).toHaveLength(1); - // 1 createEntity (rank) + 1 createRelation (type) + 1 createRelation (vote) + 1 createEntity (vote value) - expect(rank.ops).toHaveLength(4); + // 1 createEntity (ranking) + 1 createRelation (type) + 1 createRelation (vote) + 1 createEntity (vote value) + expect(ranking.ops).toHaveLength(4); - // Check rank entity creation - const rankEntityOp = rank.ops[0] as CreateEntity; - expect(rankEntityOp.type).toBe('createEntity'); - expect(rankEntityOp.id).toEqual(toGrcId(rank.id)); + // Check ranking entity creation + const rankingEntityOp = ranking.ops[0] as CreateEntity; + expect(rankingEntityOp.type).toBe('createEntity'); + expect(rankingEntityOp.id).toEqual(toGrcId(ranking.id)); - // Verify name value on rank entity - const nameValue = rankEntityOp.values.find(v => { + // Verify name value on ranking entity + const nameValue = rankingEntityOp.values.find(v => { const propBytes = v.property; return propBytes.every((b, i) => b === toGrcId(NAME_PROPERTY)[i]); }); @@ -51,36 +51,36 @@ describe('createRank', () => { expect(nameValue.value.value).toBe('My Favorite Movie'); } - // Verify rank type property (ORDINAL) - const rankTypeValue = rankEntityOp.values.find(v => { + // Verify ranking type property (ORDINAL) + const rankingTypeValue = rankingEntityOp.values.find(v => { const propBytes = v.property; return propBytes.every((b, i) => b === toGrcId(RANK_TYPE_PROPERTY)[i]); }); - expect(rankTypeValue).toBeDefined(); - expect(rankTypeValue?.value.type).toBe('text'); - if (rankTypeValue?.value.type === 'text') { - expect(rankTypeValue.value.value).toBe('ORDINAL'); + expect(rankingTypeValue).toBeDefined(); + expect(rankingTypeValue?.value.type).toBe('text'); + if (rankingTypeValue?.value.type === 'text') { + expect(rankingTypeValue.value.value).toBe('ORDINAL'); } // Check type relation to RANK_TYPE - const typeRelOp = rank.ops[1] as CreateRelation; + const typeRelOp = ranking.ops[1] as CreateRelation; expect(typeRelOp.type).toBe('createRelation'); - expect(typeRelOp.from).toEqual(toGrcId(rank.id)); + expect(typeRelOp.from).toEqual(toGrcId(ranking.id)); expect(typeRelOp.to).toEqual(toGrcId(RANK_TYPE)); expect(typeRelOp.relationType).toEqual(toGrcId(TYPES_PROPERTY)); // Check vote relation - const voteRelOp = rank.ops[2] as CreateRelation; + const voteRelOp = ranking.ops[2] as CreateRelation; expect(voteRelOp.type).toBe('createRelation'); - expect(voteRelOp.from).toEqual(toGrcId(rank.id)); + expect(voteRelOp.from).toEqual(toGrcId(ranking.id)); expect(voteRelOp.to).toEqual(toGrcId(movie1Id)); expect(voteRelOp.relationType).toEqual(toGrcId(RANK_VOTES_RELATION_TYPE)); // Check vote entity with ordinal value - const voteEntityOp = rank.ops[3] as CreateEntity; + const voteEntityOp = ranking.ops[3] as CreateEntity; expect(voteEntityOp.type).toBe('createEntity'); // biome-ignore lint/style/noNonNullAssertion: test file - we verified voteIds has 1 element - expect(voteEntityOp.id).toEqual(toGrcId(rank.voteIds[0]!)); + expect(voteEntityOp.id).toEqual(toGrcId(ranking.voteIds[0]!)); // Verify ordinal value property const ordinalValue = voteEntityOp.values.find(v => { @@ -96,19 +96,19 @@ describe('createRank', () => { } }); - it('creates an ordinal rank with multiple votes in order', () => { - const rank = createRank({ + it('creates an ordinal ranking with multiple votes in order', () => { + const ranking = createRanking({ name: 'Top 3 Movies', - rankType: 'ORDINAL', + rankingType: 'ORDINAL', votes: [{ entityId: movie1Id }, { entityId: movie2Id }, { entityId: movie3Id }], }); - expect(rank.voteIds).toHaveLength(3); + expect(ranking.voteIds).toHaveLength(3); // 1 createEntity + 1 type relation + 3 vote relations + 3 vote entities = 8 ops - expect(rank.ops).toHaveLength(8); + expect(ranking.ops).toHaveLength(8); // Extract ordinal values and verify they are in ascending order - const voteEntityOps = [rank.ops[3], rank.ops[5], rank.ops[7]] as CreateEntity[]; + const voteEntityOps = [ranking.ops[3], ranking.ops[5], ranking.ops[7]] as CreateEntity[]; const ordinalValues: string[] = []; for (const op of voteEntityOps) { @@ -131,19 +131,19 @@ describe('createRank', () => { expect(ordinalValues[1]! < ordinalValues[2]!).toBe(true); }); - it('creates an ordinal rank with optional description', () => { - const rank = createRank({ + it('creates an ordinal ranking with optional description', () => { + const ranking = createRanking({ name: 'My Movies', description: 'A ranked list of my favorite movies', - rankType: 'ORDINAL', + rankingType: 'ORDINAL', votes: [{ entityId: movie1Id }], }); - const rankEntityOp = rank.ops[0] as CreateEntity; - expect(rankEntityOp.type).toBe('createEntity'); + const rankingEntityOp = ranking.ops[0] as CreateEntity; + expect(rankingEntityOp.type).toBe('createEntity'); // Verify name value - const nameValue = rankEntityOp.values.find(v => { + const nameValue = rankingEntityOp.values.find(v => { const propBytes = v.property; return propBytes.every((b, i) => b === toGrcId(NAME_PROPERTY)[i]); }); @@ -152,18 +152,18 @@ describe('createRank', () => { expect(nameValue.value.value).toBe('My Movies'); } - // Verify rank type value - const rankTypeValue = rankEntityOp.values.find(v => { + // Verify ranking type value + const rankingTypeValue = rankingEntityOp.values.find(v => { const propBytes = v.property; return propBytes.every((b, i) => b === toGrcId(RANK_TYPE_PROPERTY)[i]); }); - expect(rankTypeValue?.value.type).toBe('text'); - if (rankTypeValue?.value.type === 'text') { - expect(rankTypeValue.value.value).toBe('ORDINAL'); + expect(rankingTypeValue?.value.type).toBe('text'); + if (rankingTypeValue?.value.type === 'text') { + expect(rankingTypeValue.value.value).toBe('ORDINAL'); } // Verify description value - const descValue = rankEntityOp.values.find(v => { + const descValue = rankingEntityOp.values.find(v => { const propBytes = v.property; return propBytes.every((b, i) => b === toGrcId(DESCRIPTION_PROPERTY)[i]); }); @@ -175,33 +175,33 @@ describe('createRank', () => { }); }); - describe('weighted ranks', () => { - it('creates a basic weighted rank with one vote', () => { - const rank = createRank({ + describe('weighted rankings', () => { + it('creates a basic weighted ranking with one vote', () => { + const ranking = createRanking({ name: 'Restaurant Rating', - rankType: 'WEIGHTED', - votes: [{ entityId: movie1Id, value: 4.5 }], + rankingType: 'WEIGHTED', + votes: [{ entityId: movie1Id, score: 4.5 }], }); - expect(rank).toBeDefined(); - expect(rank.voteIds).toHaveLength(1); - expect(rank.ops).toHaveLength(4); + expect(ranking).toBeDefined(); + expect(ranking.voteIds).toHaveLength(1); + expect(ranking.ops).toHaveLength(4); - // Check rank entity has WEIGHTED type - const rankEntityOp = rank.ops[0] as CreateEntity; - expect(rankEntityOp.type).toBe('createEntity'); + // Check ranking entity has WEIGHTED type + const rankingEntityOp = ranking.ops[0] as CreateEntity; + expect(rankingEntityOp.type).toBe('createEntity'); - const rankTypeValue = rankEntityOp.values.find(v => { + const rankingTypeValue = rankingEntityOp.values.find(v => { const propBytes = v.property; return propBytes.every((b, i) => b === toGrcId(RANK_TYPE_PROPERTY)[i]); }); - expect(rankTypeValue?.value.type).toBe('text'); - if (rankTypeValue?.value.type === 'text') { - expect(rankTypeValue.value.value).toBe('WEIGHTED'); + expect(rankingTypeValue?.value.type).toBe('text'); + if (rankingTypeValue?.value.type === 'text') { + expect(rankingTypeValue.value.value).toBe('WEIGHTED'); } - // Check vote entity with weighted value - const voteEntityOp = rank.ops[3] as CreateEntity; + // Check vote entity with weighted score + const voteEntityOp = ranking.ops[3] as CreateEntity; expect(voteEntityOp.type).toBe('createEntity'); const weightedValue = voteEntityOp.values.find(v => { @@ -215,23 +215,23 @@ describe('createRank', () => { } }); - it('creates a weighted rank with multiple votes', () => { - const rank = createRank({ + it('creates a weighted ranking with multiple votes', () => { + const ranking = createRanking({ name: 'Movie Scores', - rankType: 'WEIGHTED', + rankingType: 'WEIGHTED', votes: [ - { entityId: movie1Id, value: 9.2 }, - { entityId: movie2Id, value: 8.5 }, - { entityId: movie3Id, value: 7.8 }, + { entityId: movie1Id, score: 9.2 }, + { entityId: movie2Id, score: 8.5 }, + { entityId: movie3Id, score: 7.8 }, ], }); - expect(rank.voteIds).toHaveLength(3); - expect(rank.ops).toHaveLength(8); + expect(ranking.voteIds).toHaveLength(3); + expect(ranking.ops).toHaveLength(8); - // Verify weighted values are correct - const voteEntityOps = [rank.ops[3], rank.ops[5], rank.ops[7]] as CreateEntity[]; - const expectedValues = [9.2, 8.5, 7.8]; + // Verify weighted scores are correct + const voteEntityOps = [ranking.ops[3], ranking.ops[5], ranking.ops[7]] as CreateEntity[]; + const expectedScores = [9.2, 8.5, 7.8]; voteEntityOps.forEach((op, i) => { expect(op.type).toBe('createEntity'); @@ -241,19 +241,19 @@ describe('createRank', () => { }); expect(weightedValue?.value.type).toBe('float64'); if (weightedValue?.value.type === 'float64') { - expect(weightedValue.value.value).toBe(expectedValues[i]); + expect(weightedValue.value.value).toBe(expectedScores[i]); } }); }); - it('handles integer weighted values', () => { - const rank = createRank({ + it('handles integer weighted scores', () => { + const ranking = createRanking({ name: 'Star Ratings', - rankType: 'WEIGHTED', - votes: [{ entityId: movie1Id, value: 5 }], + rankingType: 'WEIGHTED', + votes: [{ entityId: movie1Id, score: 5 }], }); - const voteEntityOp = rank.ops[3] as CreateEntity; + const voteEntityOp = ranking.ops[3] as CreateEntity; expect(voteEntityOp.type).toBe('createEntity'); const weightedValue = voteEntityOp.values.find(v => { @@ -270,101 +270,101 @@ describe('createRank', () => { describe('provided id', () => { it('uses provided id when specified', () => { const providedId = Id('b1dc6e5c-63e1-43ba-b3d4-755b251a4ea1'); - const rank = createRank({ + const ranking = createRanking({ id: providedId, - name: 'My Rank', - rankType: 'ORDINAL', + name: 'My Ranking', + rankingType: 'ORDINAL', votes: [{ entityId: movie1Id }], }); - expect(rank.id).toBe(providedId); + expect(ranking.id).toBe(providedId); // Verify the entity op uses the provided ID - const rankEntityOp = rank.ops[0] as CreateEntity; - expect(rankEntityOp.id).toEqual(toGrcId(providedId)); + const rankingEntityOp = ranking.ops[0] as CreateEntity; + expect(rankingEntityOp.id).toEqual(toGrcId(providedId)); // Verify the type relation uses the provided ID - const typeRelOp = rank.ops[1] as CreateRelation; + const typeRelOp = ranking.ops[1] as CreateRelation; expect(typeRelOp.from).toEqual(toGrcId(providedId)); }); it('generates id when not provided', () => { - const rank = createRank({ - name: 'My Rank', - rankType: 'ORDINAL', + const ranking = createRanking({ + name: 'My Ranking', + rankingType: 'ORDINAL', votes: [{ entityId: movie1Id }], }); - expect(typeof rank.id).toBe('string'); - expect(isValid(rank.id)).toBe(true); + expect(typeof ranking.id).toBe('string'); + expect(isValid(ranking.id)).toBe(true); }); }); describe('error handling', () => { it('throws an error if the provided id is invalid', () => { expect(() => - createRank({ + createRanking({ id: 'invalid', - name: 'My Rank', - rankType: 'ORDINAL', + name: 'My Ranking', + rankingType: 'ORDINAL', votes: [{ entityId: movie1Id }], }), - ).toThrow('Invalid id: "invalid" for `id` in `createRank`'); + ).toThrow('Invalid id: "invalid" for `id` in `createRanking`'); }); it('throws an error if a vote entityId is invalid', () => { expect(() => - createRank({ - name: 'My Rank', - rankType: 'ORDINAL', + createRanking({ + name: 'My Ranking', + rankingType: 'ORDINAL', votes: [{ entityId: 'invalid-entity-id' }], }), - ).toThrow('Invalid id: "invalid-entity-id" for `entityId` in `votes` in `createRank`'); + ).toThrow('Invalid id: "invalid-entity-id" for `entityId` in `votes` in `createRanking`'); }); it('throws an error if duplicate entity IDs are in votes', () => { expect(() => - createRank({ - name: 'My Rank', - rankType: 'ORDINAL', + createRanking({ + name: 'My Ranking', + rankingType: 'ORDINAL', votes: [{ entityId: movie1Id }, { entityId: movie2Id }, { entityId: movie1Id }], }), - ).toThrow(`Duplicate entityId in votes: "${movie1Id}". Each entity can only be voted once per rank.`); + ).toThrow(`Duplicate entityId in votes: "${movie1Id}". Each entity can only be voted once per ranking.`); }); - it('throws an error for duplicate entity IDs in weighted ranks', () => { + it('throws an error for duplicate entity IDs in weighted rankings', () => { expect(() => - createRank({ + createRanking({ name: 'My Scores', - rankType: 'WEIGHTED', + rankingType: 'WEIGHTED', votes: [ - { entityId: movie1Id, value: 5 }, - { entityId: movie1Id, value: 3 }, + { entityId: movie1Id, score: 5 }, + { entityId: movie1Id, score: 3 }, ], }), - ).toThrow(`Duplicate entityId in votes: "${movie1Id}". Each entity can only be voted once per rank.`); + ).toThrow(`Duplicate entityId in votes: "${movie1Id}". Each entity can only be voted once per ranking.`); }); }); describe('empty votes', () => { - it('creates a rank with no votes', () => { - const rank = createRank({ - name: 'Empty Rank', - rankType: 'ORDINAL', + it('creates a ranking with no votes', () => { + const ranking = createRanking({ + name: 'Empty Ranking', + rankingType: 'ORDINAL', votes: [], }); - expect(rank.voteIds).toHaveLength(0); - // Only createEntity (rank) + createRelation (type) - expect(rank.ops).toHaveLength(2); + expect(ranking.voteIds).toHaveLength(0); + // Only createEntity (ranking) + createRelation (type) + expect(ranking.ops).toHaveLength(2); - // Verify rank entity was created - const rankEntityOp = rank.ops[0] as CreateEntity; - expect(rankEntityOp.type).toBe('createEntity'); - expect(rankEntityOp.id).toEqual(toGrcId(rank.id)); + // Verify ranking entity was created + const rankingEntityOp = ranking.ops[0] as CreateEntity; + expect(rankingEntityOp.type).toBe('createEntity'); + expect(rankingEntityOp.id).toEqual(toGrcId(ranking.id)); // Verify type relation was created - const typeRelOp = rank.ops[1] as CreateRelation; + const typeRelOp = ranking.ops[1] as CreateRelation; expect(typeRelOp.type).toBe('createRelation'); expect(typeRelOp.to).toEqual(toGrcId(RANK_TYPE)); }); @@ -372,31 +372,31 @@ describe('createRank', () => { describe('vote relations', () => { it('creates vote relations with correct entity references', () => { - const rank = createRank({ - name: 'My Rank', - rankType: 'ORDINAL', + const ranking = createRanking({ + name: 'My Ranking', + rankingType: 'ORDINAL', votes: [{ entityId: movie1Id }, { entityId: movie2Id }], }); - // Vote relations are at indices 2 and 4 (after rank entity and type relation) - const voteRel1 = rank.ops[2] as CreateRelation; - const voteRel2 = rank.ops[4] as CreateRelation; + // Vote relations are at indices 2 and 4 (after ranking entity and type relation) + const voteRel1 = ranking.ops[2] as CreateRelation; + const voteRel2 = ranking.ops[4] as CreateRelation; // Verify first vote relation expect(voteRel1.type).toBe('createRelation'); - expect(voteRel1.from).toEqual(toGrcId(rank.id)); + expect(voteRel1.from).toEqual(toGrcId(ranking.id)); expect(voteRel1.to).toEqual(toGrcId(movie1Id)); expect(voteRel1.relationType).toEqual(toGrcId(RANK_VOTES_RELATION_TYPE)); // biome-ignore lint/style/noNonNullAssertion: test file - we verified voteIds has 2 elements - expect(voteRel1.entity).toEqual(toGrcId(rank.voteIds[0]!)); + expect(voteRel1.entity).toEqual(toGrcId(ranking.voteIds[0]!)); // Verify second vote relation expect(voteRel2.type).toBe('createRelation'); - expect(voteRel2.from).toEqual(toGrcId(rank.id)); + expect(voteRel2.from).toEqual(toGrcId(ranking.id)); expect(voteRel2.to).toEqual(toGrcId(movie2Id)); expect(voteRel2.relationType).toEqual(toGrcId(RANK_VOTES_RELATION_TYPE)); // biome-ignore lint/style/noNonNullAssertion: test file - we verified voteIds has 2 elements - expect(voteRel2.entity).toEqual(toGrcId(rank.voteIds[1]!)); + expect(voteRel2.entity).toEqual(toGrcId(ranking.voteIds[1]!)); }); }); }); From aed5f253be34e7dc552b4c6169cdc657ffd1105c Mon Sep 17 00:00:00 2001 From: 0xjagger <194556652+0xJagger@users.noreply.github.com> Date: Fri, 23 Jan 2026 12:02:10 -0300 Subject: [PATCH 3/6] refactor(index): rename 'Rank' to 'Ranking' for consistency with updated terminology --- index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.ts b/index.ts index a7ed021..aaa9483 100644 --- a/index.ts +++ b/index.ts @@ -40,10 +40,10 @@ export * as IdUtils from './src/id-utils.js'; export * as Ipfs from './src/ipfs.js'; export { Position } from './src/position.js'; /** - * This module provides utility functions for working with ranks in the Knowledge Graph. - * Ranks allow ordering or scoring entities within a collection. + * This module provides utility functions for working with rankings in the Knowledge Graph. + * Rankings allow ordering or scoring entities within a collection. */ -export * as Rank from './src/ranks/index.js'; +export * as Ranking from './src/ranks/index.js'; /** * This module provides utility functions for working with Graph URIs in TypeScript. From abc642849235c91a7606cbe44d459ea0b1ef3cc3 Mon Sep 17 00:00:00 2001 From: 0xjagger <194556652+0xJagger@users.noreply.github.com> Date: Fri, 23 Jan 2026 12:02:17 -0300 Subject: [PATCH 4/6] refactor(ranks): update examples to use 'Ranking' terminology in create-ordinal-rank and create-weighted-rank --- examples/ranks/create-ordinal-rank.ts | 28 ++++++++++----------- examples/ranks/create-weighted-rank.ts | 34 +++++++++++++------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/examples/ranks/create-ordinal-rank.ts b/examples/ranks/create-ordinal-rank.ts index 9bb7670..7ce6e9c 100644 --- a/examples/ranks/create-ordinal-rank.ts +++ b/examples/ranks/create-ordinal-rank.ts @@ -1,11 +1,11 @@ /** - * Example: Creating an Ordinal Rank with grc-20-ts + * Example: Creating an Ordinal Ranking with grc-20-ts * - * This example demonstrates how to use the `createRank` function to create - * an ordinal (ordered) rank in the Knowledge Graph. + * This example demonstrates how to use the `createRanking` function to create + * an ordinal (ordered) ranking in the Knowledge Graph. */ -import { IdUtils, Rank } from '@graphprotocol/grc-20'; +import { IdUtils, Ranking } from '@graphprotocol/grc-20'; // For this example, we'll generate some entity IDs to represent items we want to rank. // In a real application, these would be existing entity IDs from your Knowledge Graph. @@ -14,15 +14,15 @@ const movie2Id = IdUtils.generate(); const movie3Id = IdUtils.generate(); // ============================================================================= -// Example 1: Creating an Ordinal Rank (Ordered List) +// Example 1: Creating an Ordinal Ranking (Ordered List) // ============================================================================= -// Ordinal ranks are used when you want to rank items by position (1st, 2nd, 3rd, etc.) +// Ordinal rankings are used when you want to rank items by position (1st, 2nd, 3rd, etc.) // The position is derived from the array order - no need to specify position values! -const ordinalRankResult = Rank.createRank({ +const ordinalRankingResult = Ranking.createRanking({ name: 'My Favorite Movies of 2024', description: 'A ranked list of my top movies this year', - rankType: 'ORDINAL', + rankingType: 'ORDINAL', votes: [ { entityId: movie1Id }, // 1st place { entityId: movie2Id }, // 2nd place @@ -30,14 +30,14 @@ const ordinalRankResult = Rank.createRank({ ], }); -console.log('=== Ordinal Rank Example ==='); -console.log('Rank ID:', ordinalRankResult.id); -console.log('Number of operations:', ordinalRankResult.ops.length); -console.log('Vote entity IDs:', ordinalRankResult.voteIds); +console.log('=== Ordinal Ranking Example ==='); +console.log('Ranking ID:', ordinalRankingResult.id); +console.log('Number of operations:', ordinalRankingResult.ops.length); +console.log('Vote entity IDs:', ordinalRankingResult.voteIds); -// The ops array contains all the operations needed to create this rank: +// The ops array contains all the operations needed to create this ranking: console.log('\nOperations breakdown:'); -for (const op of ordinalRankResult.ops) { +for (const op of ordinalRankingResult.ops) { if (op.type === 'createEntity') { console.log(` - createEntity`); } else if (op.type === 'createRelation') { diff --git a/examples/ranks/create-weighted-rank.ts b/examples/ranks/create-weighted-rank.ts index 10b7cee..d0ac4a0 100644 --- a/examples/ranks/create-weighted-rank.ts +++ b/examples/ranks/create-weighted-rank.ts @@ -1,11 +1,11 @@ /** - * Example: Creating a Weighted Rank with grc-20-ts + * Example: Creating a Weighted Ranking with grc-20-ts * - * This example demonstrates how to use the `createRank` function to create - * a weighted (scored) rank in the Knowledge Graph. + * This example demonstrates how to use the `createRanking` function to create + * a weighted (scored) ranking in the Knowledge Graph. */ -import { IdUtils, Rank } from '@graphprotocol/grc-20'; +import { IdUtils, Ranking } from '@graphprotocol/grc-20'; // For this example, we'll generate some entity IDs to represent items we want to rank. // In a real application, these would be existing entity IDs from your Knowledge Graph. @@ -14,30 +14,30 @@ const restaurant2Id = IdUtils.generate(); const restaurant3Id = IdUtils.generate(); // ============================================================================= -// Example 1: Creating a Weighted Rank (Scored List) +// Example 1: Creating a Weighted Ranking (Scored List) // ============================================================================= -// Weighted ranks are used when you want to assign numeric scores to items. +// Weighted rankings are used when you want to assign numeric scores to items. // Useful for ratings, reviews, or any scenario where magnitude matters. -const weightedRankResult = Rank.createRank({ +const weightedRankingResult = Ranking.createRanking({ name: 'Restaurant Ratings', description: 'My restaurant reviews', - rankType: 'WEIGHTED', + rankingType: 'WEIGHTED', votes: [ - { entityId: restaurant1Id, value: 90 }, // Can use any number and scale as needed - { entityId: restaurant2Id, value: 65 }, - { entityId: restaurant3Id, value: 50 }, + { entityId: restaurant1Id, score: 90 }, // Can use any number and scale as needed + { entityId: restaurant2Id, score: 75 }, + { entityId: restaurant3Id, score: 50.67 }, // You can also use decimal numbers ], }); -console.log('\n=== Weighted Rank Example ==='); -console.log('Rank ID:', weightedRankResult.id); -console.log('Number of operations:', weightedRankResult.ops.length); -console.log('Vote entity IDs:', weightedRankResult.voteIds); +console.log('\n=== Weighted Ranking Example ==='); +console.log('Ranking ID:', weightedRankingResult.id); +console.log('Number of operations:', weightedRankingResult.ops.length); +console.log('Vote entity IDs:', weightedRankingResult.voteIds); -// The ops array contains all the operations needed to create this rank: +// The ops array contains all the operations needed to create this ranking: console.log('\nOperations breakdown:'); -for (const op of weightedRankResult.ops) { +for (const op of weightedRankingResult.ops) { if (op.type === 'createEntity') { console.log(` - createEntity`); } else if (op.type === 'createRelation') { From 6c171eb7ea2260a3b6b7b07f5ef44be59b36489a Mon Sep 17 00:00:00 2001 From: 0xjagger <194556652+0xJagger@users.noreply.github.com> Date: Fri, 23 Jan 2026 12:15:20 -0300 Subject: [PATCH 5/6] chore: changeset --- .changeset/tasty-candles-retire.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/tasty-candles-retire.md diff --git a/.changeset/tasty-candles-retire.md b/.changeset/tasty-candles-retire.md new file mode 100644 index 0000000..74ac23a --- /dev/null +++ b/.changeset/tasty-candles-retire.md @@ -0,0 +1,5 @@ +--- +"@graphprotocol/grc-20": minor +--- + +rename ranks to ranking and vote value to score From c711e3b4ae4a2bf95287f2216846cc13eaf7e06c Mon Sep 17 00:00:00 2001 From: 0xjagger <194556652+0xJagger@users.noreply.github.com> Date: Fri, 23 Jan 2026 12:16:22 -0300 Subject: [PATCH 6/6] chore: lint --- examples/ranks/create-weighted-rank.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ranks/create-weighted-rank.ts b/examples/ranks/create-weighted-rank.ts index d0ac4a0..fed359c 100644 --- a/examples/ranks/create-weighted-rank.ts +++ b/examples/ranks/create-weighted-rank.ts @@ -25,7 +25,7 @@ const weightedRankingResult = Ranking.createRanking({ rankingType: 'WEIGHTED', votes: [ { entityId: restaurant1Id, score: 90 }, // Can use any number and scale as needed - { entityId: restaurant2Id, score: 75 }, + { entityId: restaurant2Id, score: 75 }, { entityId: restaurant3Id, score: 50.67 }, // You can also use decimal numbers ], });