Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/short-cycles-happen.md
Original file line number Diff line number Diff line change
@@ -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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -174,7 +174,7 @@ const ops: Array<GrcOp> = [];

// create an age property
const { id: agePropertyId, ops: createAgePropertyOps } = Graph.createProperty({
dataType: 'NUMBER',
dataType: 'INT64',
name: 'Age',
});
ops.push(...createAgePropertyOps);
Expand Down
18 changes: 9 additions & 9 deletions scripts/setup-rank-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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);

Expand All @@ -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);

Expand Down
19 changes: 16 additions & 3 deletions src/core/ids/system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');

/**
Expand Down
49 changes: 37 additions & 12 deletions src/graph/create-property.test.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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 () => {
Expand Down Expand Up @@ -140,7 +162,7 @@ describe('createProperty', () => {
const property = createProperty({
id: providedId,
name: 'Price',
dataType: 'NUMBER',
dataType: 'FLOAT64',
});

expect(property).toBeDefined();
Expand Down Expand Up @@ -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');
Expand All @@ -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');
Expand All @@ -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');
Expand Down
45 changes: 43 additions & 2 deletions src/graph/create-property.ts
Original file line number Diff line number Diff line change
@@ -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<ValueDataType, Id> = {
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.
Expand Down Expand Up @@ -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 };
Expand Down
14 changes: 13 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down
Loading