Skip to content

Commit 20ecb70

Browse files
committed
feat: 2nd iteration of utility functions
1 parent 9ed2be0 commit 20ecb70

11 files changed

+459
-162
lines changed

src/graph/create-attribute.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { describe, expect, it } from 'vitest';
2+
import { createAttribute } from './create-attribute.js';
3+
4+
describe('createAttribute', () => {
5+
it('creates an attribute', async () => {
6+
const attribute = await createAttribute({
7+
name: 'Name',
8+
type: 'TEXT',
9+
});
10+
expect(attribute).toBeDefined();
11+
expect(typeof attribute.id).toBe('string');
12+
expect(attribute.ops).toBeDefined();
13+
expect(attribute.ops.length).toBe(3);
14+
expect(attribute.ops[0]?.type).toBe('SET_TRIPLE');
15+
expect(attribute.ops[1]?.type).toBe('CREATE_RELATION');
16+
expect(attribute.ops[2]?.type).toBe('CREATE_RELATION');
17+
});
18+
});

src/graph/create-attribute.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { ATTRIBUTE, NAME_ATTRIBUTE, SCHEMA_TYPE, VALUE_TYPE_ATTRIBUTE } from '../core/ids/system.js';
2+
import { generate } from '../id.js';
3+
import { Relation } from '../relation.js';
4+
import { Triple } from '../triple.js';
5+
import type { Op, ValueType } from '../types.js';
6+
7+
type Params = { type: ValueType; name: string };
8+
9+
export const createAttribute = ({ type, name }: Params) => {
10+
const entityId = generate();
11+
const ops: Op[] = [];
12+
13+
// set property "Name" to the provided name
14+
const nameTripleOp = Triple.make({
15+
entityId,
16+
attributeId: NAME_ATTRIBUTE,
17+
value: {
18+
type: 'TEXT',
19+
value: name,
20+
},
21+
});
22+
ops.push(nameTripleOp);
23+
24+
// add "Property" to property "Types"
25+
const typesRelationOp = Relation.make({
26+
fromId: entityId,
27+
relationTypeId: ATTRIBUTE,
28+
toId: SCHEMA_TYPE,
29+
});
30+
ops.push(typesRelationOp);
31+
32+
// add the provided type to property "Value Types"
33+
const valueTypeRelationOp = Relation.make({
34+
fromId: entityId,
35+
relationTypeId: VALUE_TYPE_ATTRIBUTE,
36+
toId: type,
37+
});
38+
ops.push(valueTypeRelationOp);
39+
40+
return { id: entityId, ops };
41+
};

src/graph/create-entity.test.ts

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
import { describe, expect, it } from 'vitest';
2+
import { AUTHORS_ATTRIBUTE, CLAIM_TYPE, NEWS_STORY_TYPE, ROLES_ATTRIBUTE } from '../core/ids/content.js';
3+
import { TYPES_ATTRIBUTE } from '../core/ids/system.js';
4+
import { createEntity } from './create-entity.js';
5+
describe('createEntity', () => {
6+
it('creates a basic entity without properties', async () => {
7+
const entity = await createEntity({});
8+
expect(entity).toBeDefined();
9+
expect(typeof entity.id).toBe('string');
10+
expect(entity.ops).toBeDefined();
11+
expect(entity.ops).toHaveLength(0);
12+
});
13+
14+
it('creates an entity with types', async () => {
15+
const entity = await createEntity({
16+
types: [CLAIM_TYPE, NEWS_STORY_TYPE],
17+
});
18+
19+
expect(entity).toBeDefined();
20+
expect(typeof entity.id).toBe('string');
21+
expect(entity.ops).toHaveLength(2);
22+
23+
// Check first type relation
24+
expect(entity.ops[0]?.type).toBe('CREATE_RELATION');
25+
if (entity.ops[0]?.type === 'CREATE_RELATION') {
26+
expect(entity.ops[0]).toMatchObject({
27+
relation: {
28+
fromEntity: entity.id,
29+
id: entity.ops[0].relation?.id,
30+
index: entity.ops[0].relation?.index,
31+
toEntity: CLAIM_TYPE,
32+
type: TYPES_ATTRIBUTE,
33+
},
34+
type: 'CREATE_RELATION',
35+
});
36+
}
37+
38+
// Check second type relation
39+
expect(entity.ops[1]?.type).toBe('CREATE_RELATION');
40+
if (entity.ops[1]?.type === 'CREATE_RELATION') {
41+
expect(entity.ops[1]).toMatchObject({
42+
relation: {
43+
fromEntity: entity.id,
44+
id: entity.ops[1]?.relation?.id,
45+
index: entity.ops[1]?.relation?.index,
46+
toEntity: NEWS_STORY_TYPE,
47+
type: TYPES_ATTRIBUTE,
48+
},
49+
type: 'CREATE_RELATION',
50+
});
51+
}
52+
});
53+
54+
it('creates an entity with triples', async () => {
55+
const entity = await createEntity({
56+
triples: {
57+
name: { value: 'Test Entity', type: 'TEXT' },
58+
age: { value: '25', type: 'NUMBER' },
59+
},
60+
});
61+
62+
expect(entity).toBeDefined();
63+
expect(typeof entity.id).toBe('string');
64+
expect(entity.ops).toHaveLength(2);
65+
66+
// Check triples
67+
expect(entity.ops[0]?.type).toBe('SET_TRIPLE');
68+
expect(entity.ops[0]).toMatchObject({
69+
triple: {
70+
attribute: 'name',
71+
entity: entity.id,
72+
value: {
73+
type: 'TEXT',
74+
value: 'Test Entity',
75+
},
76+
},
77+
type: 'SET_TRIPLE',
78+
});
79+
80+
expect(entity.ops[1]?.type).toBe('SET_TRIPLE');
81+
expect(entity.ops[1]).toMatchObject({
82+
triple: {
83+
attribute: 'age',
84+
entity: entity.id,
85+
value: { type: 'NUMBER', value: '25' },
86+
},
87+
type: 'SET_TRIPLE',
88+
});
89+
});
90+
91+
it('creates an entity with relations', async () => {
92+
const entity = await createEntity({
93+
relations: [
94+
{ type: AUTHORS_ATTRIBUTE, to: 'some-author-id' },
95+
{ type: ROLES_ATTRIBUTE, to: 'some-role-id' },
96+
],
97+
});
98+
99+
expect(entity).toBeDefined();
100+
expect(typeof entity.id).toBe('string');
101+
expect(entity.ops).toHaveLength(2);
102+
103+
// Check relations
104+
expect(entity.ops[0]?.type).toBe('CREATE_RELATION');
105+
if (entity.ops[0]?.type === 'CREATE_RELATION') {
106+
expect(entity.ops[0]).toMatchObject({
107+
relation: {
108+
fromEntity: entity.id,
109+
id: entity.ops[0]?.relation?.id,
110+
index: entity.ops[0]?.relation?.index,
111+
toEntity: 'some-author-id',
112+
type: AUTHORS_ATTRIBUTE,
113+
},
114+
type: 'CREATE_RELATION',
115+
});
116+
}
117+
118+
expect(entity.ops[1]?.type).toBe('CREATE_RELATION');
119+
if (entity.ops[1]?.type === 'CREATE_RELATION') {
120+
expect(entity.ops[1]).toMatchObject({
121+
relation: {
122+
fromEntity: entity.id,
123+
id: entity.ops[1]?.relation?.id,
124+
index: entity.ops[1]?.relation?.index,
125+
toEntity: 'some-role-id',
126+
type: ROLES_ATTRIBUTE,
127+
},
128+
type: 'CREATE_RELATION',
129+
});
130+
}
131+
});
132+
133+
it('creates an entity with types, triples, and relations', async () => {
134+
const entity = await createEntity({
135+
types: [CLAIM_TYPE, NEWS_STORY_TYPE],
136+
triples: {
137+
name: { value: 'Test Entity', type: 'TEXT' },
138+
},
139+
relations: [{ type: AUTHORS_ATTRIBUTE, to: 'some-author-id' }],
140+
});
141+
142+
expect(entity).toBeDefined();
143+
expect(typeof entity.id).toBe('string');
144+
expect(entity.ops).toHaveLength(4);
145+
146+
// Check type relations
147+
expect(entity.ops[0]?.type).toBe('CREATE_RELATION');
148+
expect(entity.ops[0]).toMatchObject({
149+
relation: {
150+
fromEntity: entity.id,
151+
toEntity: CLAIM_TYPE,
152+
type: TYPES_ATTRIBUTE,
153+
},
154+
type: 'CREATE_RELATION',
155+
});
156+
157+
expect(entity.ops[1]?.type).toBe('CREATE_RELATION');
158+
expect(entity.ops[1]).toMatchObject({
159+
relation: {
160+
fromEntity: entity.id,
161+
toEntity: NEWS_STORY_TYPE,
162+
type: TYPES_ATTRIBUTE,
163+
},
164+
type: 'CREATE_RELATION',
165+
});
166+
167+
// Check triple
168+
expect(entity.ops[2]?.type).toBe('SET_TRIPLE');
169+
expect(entity.ops[2]).toMatchObject({
170+
triple: {
171+
attribute: 'name',
172+
entity: entity.id,
173+
value: { type: 'TEXT', value: 'Test Entity' },
174+
},
175+
type: 'SET_TRIPLE',
176+
});
177+
178+
// Check relation
179+
expect(entity.ops[3]?.type).toBe('CREATE_RELATION');
180+
expect(entity.ops[3]).toMatchObject({
181+
relation: {
182+
fromEntity: entity.id,
183+
toEntity: 'some-author-id',
184+
type: AUTHORS_ATTRIBUTE,
185+
},
186+
type: 'CREATE_RELATION',
187+
});
188+
});
189+
});

src/graph/create-entity.ts

Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,58 +2,52 @@ import { TYPES_ATTRIBUTE } from '../core/ids/system.js';
22
import { generate } from '../id.js';
33
import { Relation } from '../relation.js';
44
import { Triple } from '../triple.js';
5-
import type { CreateRelationOp, Op, SetTripleOp, ValueType } from '../types.js';
5+
import type { Op, ValueType } from '../types.js';
66

77
type Params = {
8-
attributes?: {
9-
[filedName: string]: string;
10-
};
11-
mapping?: {
12-
[filedName: string]: { id: string; type: ValueType };
13-
};
8+
triples?: Record<string, { value: string; type: ValueType }>;
149
types?: Array<string>;
15-
relations?: Array<{
16-
relationTypeId: string;
17-
toId: string;
18-
}>;
10+
relations?: Array<{ type: string; to: string; triple?: { attributeId: string; value: string } }>;
1911
};
2012

21-
export const createEntity = async ({ attributes, mapping, types, relations }: Params) => {
13+
export const createEntity = ({ triples, types, relations }: Params) => {
2214
const id = generate();
2315
const ops: Array<Op> = [];
24-
if (attributes && mapping) {
25-
for (const [fieldName, value] of Object.entries(attributes)) {
26-
const attributeMapping = mapping[fieldName];
27-
if (!attributeMapping) {
28-
throw new Error(`Attribute ID for field ${fieldName} not found`);
29-
}
30-
const setTripleOp: SetTripleOp = Triple.make({
31-
entityId: id,
32-
attributeId: attributeMapping.id,
33-
value: {
34-
type: attributeMapping.type,
35-
value,
36-
},
37-
});
38-
39-
ops.push(setTripleOp);
40-
}
41-
}
4216

17+
// add property "Types" to the provided types
4318
if (types) {
44-
// add types
4519
for (const typeId of types) {
46-
const setRelationOp: CreateRelationOp = Relation.make({
20+
const typeRelationOp = Relation.make({
4721
fromId: id,
4822
relationTypeId: TYPES_ATTRIBUTE,
4923
toId: typeId,
5024
});
51-
ops.push(setRelationOp);
25+
ops.push(typeRelationOp);
5226
}
5327
}
5428

29+
// set properties with the provided values
30+
if (triples) {
31+
for (const [attributeId, value] of Object.entries(triples)) {
32+
const propertyTripleOp = Triple.make({
33+
entityId: id,
34+
attributeId,
35+
value,
36+
});
37+
ops.push(propertyTripleOp);
38+
}
39+
}
40+
41+
// add relations with the provided relations
5542
if (relations) {
56-
// TODO add relations
43+
for (const relation of relations) {
44+
const relationOp = Relation.make({
45+
fromId: id,
46+
relationTypeId: relation.type,
47+
toId: relation.to,
48+
});
49+
ops.push(relationOp);
50+
}
5751
}
5852

5953
return { id, ops };

src/graph/create-relation-type.ts

Lines changed: 16 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,28 @@
1-
import { ATTRIBUTE, NAME_ATTRIBUTE, SCHEMA_TYPE, TYPES_ATTRIBUTE } from '../core/ids/system.js';
2-
import { generate } from '../id.js';
1+
import { ATTRIBUTE, SCHEMA_TYPE } from '../core/ids/system.js';
32
import { Relation } from '../relation.js';
4-
import { Triple } from '../triple.js';
5-
import type { CreateRelationOp, Op, SetTripleOp } from '../types.js';
3+
import type { Op } from '../types.js';
4+
import { createType } from './create-type.js';
65

76
type Params = {
8-
from: string;
9-
to: string;
107
name: string;
8+
properties?: Array<string>;
119
};
1210

13-
export const createRelationType = async ({ from, to, name }: Params) => {
14-
const id = generate();
11+
export const createRelationType = ({ name, properties }: Params) => {
1512
const ops: Op[] = [];
13+
const { id, ops: createTypeOps } = createType({ name, properties });
14+
ops.push(...createTypeOps);
1615

17-
const nameTripleOp: SetTripleOp = Triple.make({
18-
entityId: id,
19-
attributeId: NAME_ATTRIBUTE,
20-
value: {
21-
type: 'TEXT',
22-
value: name,
23-
},
24-
});
25-
ops.push(nameTripleOp);
26-
27-
const setRelationOp: CreateRelationOp = Relation.make({
28-
fromId: id,
29-
relationTypeId: TYPES_ATTRIBUTE,
30-
toId: SCHEMA_TYPE, // this sets the relation type to be a typ type
31-
});
32-
ops.push(setRelationOp);
33-
34-
const setRelationOp2: CreateRelationOp = Relation.make({
16+
// add "Property" to property "Types"
17+
const typesRelationOp = Relation.make({
3518
fromId: id,
36-
relationTypeId: TYPES_ATTRIBUTE,
37-
toId: ATTRIBUTE, // this sets the relation type to be an "property" type
19+
relationTypeId: ATTRIBUTE,
20+
toId: SCHEMA_TYPE,
3821
});
39-
ops.push(setRelationOp2);
40-
41-
// TODO relations
22+
ops.push(typesRelationOp);
4223

43-
return { id, ops };
24+
return {
25+
id,
26+
ops,
27+
};
4428
};

0 commit comments

Comments
 (0)