Skip to content

Commit 7dc2cac

Browse files
committed
change schema structure
1 parent b38b8c2 commit 7dc2cac

File tree

2 files changed

+76
-102
lines changed

2 files changed

+76
-102
lines changed

apps/events/src/schema.ts

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,26 @@ import { createFunctions, type } from "graph-framework";
1515
// end autogenerated
1616

1717
export const schema = {
18-
attributes: {
19-
// ...spaceAttributes,
20-
name: type.Text,
21-
age: type.Number,
22-
isActive: type.Checkbox,
23-
email: type.Text,
24-
},
25-
relations: {
26-
// friends: type.Relation(["User", "Person"], {
27-
// cardinality: "many", // "one" | "many"
28-
// }),
29-
// soulmate: type.Relation(["User", "Person"], {
30-
// cardinality: "one", // "one" | "many"
31-
// }),
32-
},
18+
// relations: {
19+
// // friends: type.Relation(["User", "Person"], {
20+
// // cardinality: "many", // "one" | "many"
21+
// // }),
22+
// // soulmate: type.Relation(["User", "Person"], {
23+
// // cardinality: "one", // "one" | "many"
24+
// // }),
25+
// },
3326
types: {
34-
Person: ["name", "age"] as const,
35-
User: ["name", "email"] as const,
36-
Event: ["name"] as const,
27+
Person: {
28+
name: type.Text,
29+
age: type.Number,
30+
},
31+
User: {
32+
name: type.Text,
33+
email: type.Text,
34+
},
35+
Event: {
36+
name: type.Text,
37+
},
3738
},
3839
// imports: {
3940
// attributes: {},

packages/graph-framework/context.tsx

Lines changed: 57 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -28,82 +28,62 @@ export const repo = new Repo({
2828
network: [],
2929
});
3030

31-
// Function to create schema functions
32-
export function createFunctions<
33-
Attributes extends { [attrName: string]: S.Schema<any> },
34-
Types extends { [typeName: string]: ReadonlyArray<keyof Attributes> },
35-
>({ attributes, types }: { attributes: Attributes; types: Types }) {
36-
// Build attribute schemas
37-
const attributeSchemas: {
38-
[K in keyof Attributes]: Attributes[K];
39-
} = attributes;
40-
41-
// Build type schemas
42-
const typeSchemas: {
43-
[K in keyof Types]: S.Schema<{
44-
[AttrName in Types[K][number]]: S.Schema.Type<
45-
(typeof attributeSchemas)[AttrName]
46-
>;
47-
}>;
48-
} = {} as any;
49-
50-
for (const typeName in types) {
51-
const attrNames = types[typeName as keyof Types];
52-
const attrSchemaEntries: any = {};
53-
for (const attrName of attrNames) {
54-
const attrSchema = attributeSchemas[attrName];
55-
if (!attrSchema) {
56-
throw new Error(`Attribute ${String(attrName)} is not defined`);
57-
}
58-
attrSchemaEntries[attrName as string] = attrSchema;
59-
}
60-
typeSchemas[typeName as keyof Types] = S.Struct(attrSchemaEntries) as any;
61-
}
31+
// Helper type to extract schema type
32+
type SchemaType<T> = T extends S.Schema<any, infer A> ? A : never;
6233

63-
// Type for merged types
64-
type TypeSchemasMap = typeof typeSchemas;
65-
66-
type TypeSchemaTypes<T extends keyof TypeSchemasMap> = S.Schema.Type<
67-
TypeSchemasMap[T]
68-
>;
69-
70-
type UnionToIntersection<U> = (
71-
U extends any ? (k: U) => void : never
72-
) extends (k: infer I) => void
73-
? I
74-
: never;
75-
76-
type MergedType<T extends (keyof TypeSchemasMap)[]> = UnionToIntersection<
77-
TypeSchemaTypes<T[number]>
78-
>;
79-
80-
// Helper function to build merged schema
81-
function buildMergedSchema<TypeNames extends (keyof TypeSchemasMap)[]>(
82-
typesToCombine: [...TypeNames]
83-
): S.Schema<any> {
84-
const mergedFields: Record<string, S.Schema<any>> = {};
85-
86-
for (const typeName of typesToCombine) {
87-
const schema = typeSchemas[typeName];
88-
const structSchema = schema as S.Schema<any> & {
89-
fields: Record<string, S.Schema<any>>;
90-
};
34+
// Type for the schema structure
35+
export type SchemaDefinition = {
36+
types: Record<string, Record<string, S.Schema<any, any>>>;
37+
};
9138

92-
if ("fields" in structSchema) {
93-
Object.assign(mergedFields, structSchema.fields);
94-
} else {
95-
throw new Error(`Schema for type ${String(typeName)} is not a struct`);
96-
}
97-
}
39+
// Extract all possible keys from schema types
40+
type EntityKeys<T extends SchemaDefinition> = keyof T["types"] & string;
41+
42+
// Get merged type from array of keys
43+
type MergedEntityType<
44+
T extends SchemaDefinition,
45+
Keys extends readonly EntityKeys<T>[],
46+
> = UnionToIntersection<
47+
{
48+
[K in Keys[number]]: {
49+
[P in keyof T["types"][K]]: SchemaType<T["types"][K][P]>;
50+
};
51+
}[Keys[number]]
52+
>;
9853

99-
return S.Struct(mergedFields);
100-
}
54+
// Helper type to convert union to intersection
55+
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
56+
k: infer I
57+
) => void
58+
? I
59+
: never;
10160

61+
// Function to create schema functions
62+
export function createFunctions<T extends SchemaDefinition>(schema: T) {
10263
// Create a React Context to provide the schema
10364
type SpaceContextProps = {
10465
id: string;
10566
};
10667

68+
function buildMergedSchema<K extends readonly EntityKeys<T>[]>(
69+
types: [...K]
70+
): S.Schema<any, MergedEntityType<T, K>> {
71+
// Create a record of all properties and their schemas
72+
const propertySchemas = types.reduce(
73+
(acc, type) => {
74+
const typeSchema = schema.types[type];
75+
return { ...acc, ...typeSchema };
76+
},
77+
{} as Record<string, S.Schema<any, any>>
78+
);
79+
80+
// Convert the record to a struct schema
81+
return S.Struct(propertySchemas) as unknown as S.Schema<
82+
any,
83+
MergedEntityType<T, K>
84+
>;
85+
}
86+
10787
const SpaceContext = createContext<SpaceContextProps | undefined>(undefined);
10888

10989
function SpaceProvider({ children, id }: SpaceProviderProps) {
@@ -137,10 +117,10 @@ export function createFunctions<
137117
const id = useSpaceId();
138118
const [, changeDoc] = useDocument<DocumentContent>(id as AnyDocumentId);
139119

140-
function createEntity<TypeNames extends (keyof TypeSchemasMap)[]>(
141-
types: [...TypeNames],
142-
data: MergedType<TypeNames>
143-
): MergedType<TypeNames> {
120+
function createEntity<K extends readonly EntityKeys<T>[]>(
121+
types: [...K],
122+
data: MergedEntityType<T, K>
123+
): MergedEntityType<T, K> {
144124
if (types.length === 0) {
145125
throw new Error("Entity must have at least one type");
146126
}
@@ -156,7 +136,7 @@ export function createFunctions<
156136
doc.entities[entityId] = { ...result, types };
157137
});
158138

159-
return result as MergedType<TypeNames>;
139+
return result as MergedEntityType<T, K>;
160140
}
161141

162142
return createEntity;
@@ -194,17 +174,10 @@ export function createFunctions<
194174
return deleteEntity;
195175
}
196176

197-
function useQuery<TypeNames extends (keyof TypeSchemasMap)[]>({
177+
function useQuery<K extends readonly EntityKeys<T>[]>({
198178
types,
199-
where,
200179
}: {
201-
types: [...TypeNames];
202-
where?: {
203-
[AttrName in keyof Attributes]?: {
204-
equals?: S.Schema.Type<Attributes[AttrName]>;
205-
contains?: S.Schema.Type<Attributes[AttrName]>;
206-
};
207-
};
180+
types: [...K];
208181
}) {
209182
const prevEntitiesRef = useRef<any>({});
210183
const id = useSpaceId();
@@ -234,7 +207,7 @@ export function createFunctions<
234207

235208
const entities = useSyncExternalStore(
236209
subscribe,
237-
(): Record<string, MergedType<TypeNames>> => {
210+
(): Record<string, MergedEntityType<T, K>> => {
238211
const doc = handle?.docSync();
239212
if (!doc) {
240213
if (fastDeepEqual(prevEntitiesRef.current, {})) {
@@ -246,11 +219,11 @@ export function createFunctions<
246219
}
247220

248221
// create filteredEntities object with only entities that include all the types
249-
const filteredEntities: Record<string, MergedType<TypeNames>> = {};
222+
const filteredEntities: Record<string, MergedEntityType<T, K>> = {};
250223
for (const entityId in doc.entities) {
251224
const entity = doc.entities[entityId];
252225
if (types.every((type) => entity.types.includes(type as string))) {
253-
filteredEntities[entityId] = entity as MergedType<TypeNames>;
226+
filteredEntities[entityId] = entity as MergedEntityType<T, K>;
254227
}
255228
}
256229

0 commit comments

Comments
 (0)