diff --git a/.changeset/short-cycles-happen.md b/.changeset/short-cycles-happen.md new file mode 100644 index 0000000..609ed35 --- /dev/null +++ b/.changeset/short-cycles-happen.md @@ -0,0 +1,5 @@ +--- +"@graphprotocol/grc-20": patch +--- + +fix Graph.createProperty to work with the new grc-20 spec. It accepts the new data types diff --git a/README.md b/README.md index 52aa413..e4396c6 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ import { Graph } from '@graphprotocol/grc-20'; // create a property const propertyResult = Graph.createProperty({ name: 'name of the property', - dataType: 'STRING', // STRING | NUMBER | TIME | POINT | BOOLEAN | RELATION, + dataType: 'TEXT', // BOOLEAN | INT64 | FLOAT64 | DECIMAL | TEXT | BYTES | DATE | TIME | DATETIME | SCHEDULE | POINT | EMBEDDING | RELATION }); // create a type @@ -174,7 +174,7 @@ const ops: Array = []; // create an age property const { id: agePropertyId, ops: createAgePropertyOps } = Graph.createProperty({ - dataType: 'NUMBER', + dataType: 'INT64', name: 'Age', }); ops.push(...createAgePropertyOps); diff --git a/scripts/setup-rank-types.ts b/scripts/setup-rank-types.ts index 13a649a..29b24a9 100644 --- a/scripts/setup-rank-types.ts +++ b/scripts/setup-rank-types.ts @@ -2,10 +2,10 @@ * Setup script for Rank types in the knowledge graph. * * This script generates the Ops needed to create the Rank schema types: - * - RANK_TYPE_PROPERTY: A STRING property storing ORDINAL/WEIGHTED + * - RANK_TYPE_PROPERTY: A TEXT property storing ORDINAL/WEIGHTED * - RANK_VOTES_RELATION_TYPE: A RELATION property linking rank to voted entities - * - VOTE_ORDINAL_VALUE_PROPERTY: A STRING property storing fractional indexing position - * - VOTE_WEIGHTED_VALUE_PROPERTY: A NUMBER property storing numeric score + * - VOTE_ORDINAL_VALUE_PROPERTY: A TEXT property storing fractional indexing position + * - VOTE_WEIGHTED_VALUE_PROPERTY: A FLOAT64 property storing numeric score * - RANK_TYPE: A Type entity representing a Rank * * Usage: import { ops } from './scripts/setup-rank-types.js' @@ -25,12 +25,12 @@ import { createType } from '../src/graph/create-type.js'; const generateRankTypeOps = (): GrcOp[] => { const ops: GrcOp[] = []; - // 1. Create RANK_TYPE_PROPERTY - A STRING property storing ORDINAL/WEIGHTED + // 1. Create RANK_TYPE_PROPERTY - A TEXT property storing ORDINAL/WEIGHTED const rankTypeProperty = createProperty({ id: RANK_TYPE_PROPERTY, name: 'Rank Type', description: 'The type of rank: ORDINAL (ordered list) or WEIGHTED (scored values)', - dataType: 'STRING', + dataType: 'TEXT', }); ops.push(...rankTypeProperty.ops); @@ -43,21 +43,21 @@ const generateRankTypeOps = (): GrcOp[] => { }); ops.push(...rankVotesRelationType.ops); - // 3. Create VOTE_ORDINAL_VALUE_PROPERTY - A STRING property for fractional indexing + // 3. Create VOTE_ORDINAL_VALUE_PROPERTY - A TEXT property for fractional indexing const voteOrdinalValueProperty = createProperty({ id: VOTE_ORDINAL_VALUE_PROPERTY, name: 'Vote Ordinal Value', description: 'Fractional indexing string for ordered rank positions', - dataType: 'STRING', + dataType: 'TEXT', }); ops.push(...voteOrdinalValueProperty.ops); - // 4. Create VOTE_WEIGHTED_VALUE_PROPERTY - A NUMBER property for numeric scores + // 4. Create VOTE_WEIGHTED_VALUE_PROPERTY - A FLOAT64 property for numeric scores const voteWeightedValueProperty = createProperty({ id: VOTE_WEIGHTED_VALUE_PROPERTY, name: 'Vote Weighted Value', description: 'Numeric score for weighted rank values', - dataType: 'NUMBER', + dataType: 'FLOAT64', }); ops.push(...voteWeightedValueProperty.ops); diff --git a/src/core/ids/system.ts b/src/core/ids/system.ts index 3801fbb..f04f744 100644 --- a/src/core/ids/system.ts +++ b/src/core/ids/system.ts @@ -15,13 +15,26 @@ export const TABS_PROPERTY = Id('4d9cba1c4766469881cd3273891a018b'); export const BLOCKS = Id('beaba5cba67741a8b35377030613fc70'); -/** Value types */ +/** Data types */ +export const BOOLEAN = Id('7aa4792eeacd41868272fa7fc18298ac'); +export const INT64 = Id('149fd752d9d04f80820d1d942eea7841'); +export const FLOAT64 = Id('9b597aaec31c46c88565a370da0c2a65'); +export const DECIMAL = Id('a3288c22a0564f6fb409fbcccb2c118c'); +export const TEXT = Id('9edb6fcce4544aa5861139d7f024c010'); +export const BYTES = Id('66b433247667496899b48a89bd1de22b'); +export const DATE = Id('e661d10292794449a22367dbae1be05a'); +export const TIME = Id('ad75102b03c04d59903813ede9482742'); +export const DATETIME = Id('167664f668f840e1976b20bd16ed8d47'); +export const SCHEDULE = Id('caf4dd12ba4844b99171aff6c1313b50'); +export const POINT = Id('df250d17e364413d97792ddaae841e34'); +export const EMBEDDING = Id('f732849378ba4577a33fac5f1c964f18'); +export const RELATION = Id('4b6d9fc1fbfe474c861c83398e1b50d9'); + +export const DATA_TYPE = Id('6d29d57849bb4959baf72cc696b1671a'); export const URL = Id('283127c96142468492ed90b0ebc7f29a'); export const IMAGE = Id('f3f790c4c74e4d23a0a91e8ef84e30d9'); -export const RELATION = Id('4b6d9fc1fbfe474c861c83398e1b50d9'); - export const SPACE_TYPE = Id('362c1dbddc6444bba3c4652f38a642d7'); /** diff --git a/src/graph/create-property.test.ts b/src/graph/create-property.test.ts index d45af0c..241cb5b 100644 --- a/src/graph/create-property.test.ts +++ b/src/graph/create-property.test.ts @@ -1,7 +1,15 @@ import type { CreateEntity, CreateRelation } from '@geoprotocol/grc-20'; import { describe, expect, it } from 'vitest'; import { JOB_TYPE, ROLES_PROPERTY } from '../core/ids/content.js'; -import { NAME_PROPERTY, PROPERTY, RELATION_VALUE_RELATIONSHIP_TYPE, TYPES_PROPERTY } from '../core/ids/system.js'; +import { + DATA_TYPE, + FLOAT64, + NAME_PROPERTY, + PROPERTY, + RELATION_VALUE_RELATIONSHIP_TYPE, + TEXT, + TYPES_PROPERTY, +} from '../core/ids/system.js'; import { Id } from '../id.js'; import { toGrcId } from '../id-utils.js'; import { createProperty } from './create-property.js'; @@ -11,13 +19,13 @@ describe('createProperty', () => { const property = createProperty({ name: 'Disclaimer', description: 'This is a disclaimer', - dataType: 'STRING', + dataType: 'TEXT', }); expect(property).toBeDefined(); expect(typeof property.id).toBe('string'); expect(property.ops).toBeDefined(); - // 1 createEntity + 1 createRelation (type) - expect(property.ops.length).toBe(2); + // 1 createEntity + 1 createRelation (type) + 1 createRelation (data type) + expect(property.ops.length).toBe(3); // Check entity creation const entityOp = property.ops[0] as CreateEntity; @@ -41,20 +49,27 @@ describe('createProperty', () => { expect(typeRelOp.from).toEqual(toGrcId(property.id)); expect(typeRelOp.to).toEqual(toGrcId(PROPERTY)); expect(typeRelOp.relationType).toEqual(toGrcId(TYPES_PROPERTY)); + + // Check data type relation to TEXT + const dataTypeRelOp = property.ops[2] as CreateRelation; + expect(dataTypeRelOp.type).toBe('createRelation'); + expect(dataTypeRelOp.from).toEqual(toGrcId(property.id)); + expect(dataTypeRelOp.to).toEqual(toGrcId(TEXT)); + expect(dataTypeRelOp.relationType).toEqual(toGrcId(DATA_TYPE)); }); - it('creates a NUMBER property', async () => { + it('creates a FLOAT64 property', async () => { const property = createProperty({ name: 'Price', description: 'The price of the product', - dataType: 'NUMBER', + dataType: 'FLOAT64', }); expect(property).toBeDefined(); expect(typeof property.id).toBe('string'); expect(property.ops).toBeDefined(); - // 1 createEntity + 1 createRelation (type) - expect(property.ops.length).toBe(2); + // 1 createEntity + 1 createRelation (type) + 1 createRelation (data type) + expect(property.ops.length).toBe(3); // Check entity creation const entityOp = property.ops[0] as CreateEntity; @@ -67,6 +82,13 @@ describe('createProperty', () => { expect(typeRelOp.from).toEqual(toGrcId(property.id)); expect(typeRelOp.to).toEqual(toGrcId(PROPERTY)); expect(typeRelOp.relationType).toEqual(toGrcId(TYPES_PROPERTY)); + + // Check data type relation to FLOAT64 + const dataTypeRelOp = property.ops[2] as CreateRelation; + expect(dataTypeRelOp.type).toBe('createRelation'); + expect(dataTypeRelOp.from).toEqual(toGrcId(property.id)); + expect(dataTypeRelOp.to).toEqual(toGrcId(FLOAT64)); + expect(dataTypeRelOp.relationType).toEqual(toGrcId(DATA_TYPE)); }); it('creates a RELATION property', async () => { @@ -140,7 +162,7 @@ describe('createProperty', () => { const property = createProperty({ id: providedId, name: 'Price', - dataType: 'NUMBER', + dataType: 'FLOAT64', }); expect(property).toBeDefined(); @@ -187,7 +209,8 @@ describe('createProperty', () => { }); expect(property).toBeDefined(); - expect(property.ops.length).toBe(2); + // 1 createEntity + 1 createRelation (type) + 1 createRelation (data type) + expect(property.ops.length).toBe(3); const entityOp = property.ops[0] as CreateEntity; expect(entityOp.type).toBe('createEntity'); @@ -204,7 +227,8 @@ describe('createProperty', () => { }); expect(property).toBeDefined(); - expect(property.ops.length).toBe(2); + // 1 createEntity + 1 createRelation (type) + 1 createRelation (data type) + expect(property.ops.length).toBe(3); const typeRelOp = property.ops[1] as CreateRelation; expect(typeRelOp.type).toBe('createRelation'); @@ -218,7 +242,8 @@ describe('createProperty', () => { }); expect(property).toBeDefined(); - expect(property.ops.length).toBe(2); + // 1 createEntity + 1 createRelation (type) + 1 createRelation (data type) + expect(property.ops.length).toBe(3); const typeRelOp = property.ops[1] as CreateRelation; expect(typeRelOp.type).toBe('createRelation'); diff --git a/src/graph/create-property.ts b/src/graph/create-property.ts index 2326abf..7ecb894 100644 --- a/src/graph/create-property.ts +++ b/src/graph/create-property.ts @@ -1,11 +1,43 @@ import { type Op as GrcOp, createRelation as grcCreateRelation } from '@geoprotocol/grc-20'; -import { PROPERTY, RELATION_VALUE_RELATIONSHIP_TYPE, TYPES_PROPERTY } from '../core/ids/system.js'; +import { + BOOLEAN, + BYTES, + DATA_TYPE, + DATE, + DATETIME, + DECIMAL, + EMBEDDING, + FLOAT64, + INT64, + POINT, + PROPERTY, + RELATION_VALUE_RELATIONSHIP_TYPE, + SCHEDULE, + TEXT, + TIME, + TYPES_PROPERTY, +} from '../core/ids/system.js'; import { Id } from '../id.js'; import { assertValid, generate, toGrcId } from '../id-utils.js'; -import type { CreatePropertyParams, CreateResult } from '../types.js'; +import type { CreatePropertyParams, CreateResult, ValueDataType } from '../types.js'; import { createEntity } from './create-entity.js'; import { createRelation } from './create-relation.js'; +const VALUE_DATA_TYPE_TO_ID: Record = { + BOOLEAN, + INT64, + FLOAT64, + DECIMAL, + TEXT, + BYTES, + DATE, + TIME, + DATETIME, + SCHEDULE, + POINT, + EMBEDDING, +}; + /** * Creates a property with the given name, description, cover, and dataType. * All IDs passed to this function (cover, relation value types, properties) are validated. @@ -90,6 +122,15 @@ export const createProperty = (params: CreatePropertyParams): CreateResult => { ops.push(...relationOps); } } + } else { + // add the data type relation for value types + const dataTypeId = VALUE_DATA_TYPE_TO_ID[params.dataType]; + const { ops: relationOps } = createRelation({ + fromEntity: entityId, + toEntity: dataTypeId, + type: DATA_TYPE, + }); + ops.push(...relationOps); } return { id: Id(entityId), ops }; diff --git a/src/types.ts b/src/types.ts index 6b9a1bb..feb8394 100644 --- a/src/types.ts +++ b/src/types.ts @@ -7,7 +7,19 @@ import type { Id } from './id.js'; export type { GrcOp }; -export type ValueDataType = 'STRING' | 'NUMBER' | 'BOOLEAN' | 'TIME' | 'POINT'; +export type ValueDataType = + | 'BOOLEAN' + | 'INT64' + | 'FLOAT64' + | 'DECIMAL' + | 'TEXT' + | 'BYTES' + | 'DATE' + | 'TIME' + | 'DATETIME' + | 'SCHEDULE' + | 'POINT' + | 'EMBEDDING'; export type DataType = ValueDataType | 'RELATION';