diff --git a/.changeset/icy-emus-tap.md b/.changeset/icy-emus-tap.md index a7593697..278e22e7 100644 --- a/.changeset/icy-emus-tap.md +++ b/.changeset/icy-emus-tap.md @@ -15,7 +15,7 @@ export class User extends Entity.Class('User')({ After: ```ts -export const User = EntitySchema( +export const User = Entity.Schema( { name: Type.String }, { types: [Id('bffa181e-a333-495b-949c-57f2831d7eca')], diff --git a/apps/events/src/schema.ts b/apps/events/src/schema.ts index fcefe3d8..c8850a52 100644 --- a/apps/events/src/schema.ts +++ b/apps/events/src/schema.ts @@ -1,6 +1,6 @@ -import { EntitySchema, Id, Type } from '@graphprotocol/hypergraph'; +import { Entity, Id, Type } from '@graphprotocol/hypergraph'; -export const User = EntitySchema( +export const User = Entity.Schema( { name: Type.String }, { types: [Id('bffa181e-a333-495b-949c-57f2831d7eca')], @@ -10,7 +10,7 @@ export const User = EntitySchema( }, ); -export const Todo = EntitySchema( +export const Todo = Entity.Schema( { name: Type.String, completed: Type.Boolean, @@ -26,7 +26,7 @@ export const Todo = EntitySchema( }, ); -export const Todo2 = EntitySchema( +export const Todo2 = Entity.Schema( { name: Type.String, checked: Type.Boolean, @@ -50,7 +50,7 @@ export const Todo2 = EntitySchema( }, ); -export const JobOffer = EntitySchema( +export const JobOffer = Entity.Schema( { name: Type.String, salary: Type.Number, @@ -64,7 +64,7 @@ export const JobOffer = EntitySchema( }, ); -export const Company = EntitySchema( +export const Company = Entity.Schema( { name: Type.String, jobOffers: Type.Relation(JobOffer), @@ -78,7 +78,7 @@ export const Company = EntitySchema( }, ); -export const Event = EntitySchema( +export const Event = Entity.Schema( { name: Type.String, description: Type.optional(Type.String), @@ -94,7 +94,7 @@ export const Event = EntitySchema( }, ); -export const Image = EntitySchema( +export const Image = Entity.Schema( { url: Type.String, }, @@ -106,7 +106,7 @@ export const Image = EntitySchema( }, ); -export const Project = EntitySchema( +export const Project = Entity.Schema( { name: Type.String, description: Type.optional(Type.String), diff --git a/apps/privy-login-example/src/schema.ts b/apps/privy-login-example/src/schema.ts index fcefe3d8..c8850a52 100644 --- a/apps/privy-login-example/src/schema.ts +++ b/apps/privy-login-example/src/schema.ts @@ -1,6 +1,6 @@ -import { EntitySchema, Id, Type } from '@graphprotocol/hypergraph'; +import { Entity, Id, Type } from '@graphprotocol/hypergraph'; -export const User = EntitySchema( +export const User = Entity.Schema( { name: Type.String }, { types: [Id('bffa181e-a333-495b-949c-57f2831d7eca')], @@ -10,7 +10,7 @@ export const User = EntitySchema( }, ); -export const Todo = EntitySchema( +export const Todo = Entity.Schema( { name: Type.String, completed: Type.Boolean, @@ -26,7 +26,7 @@ export const Todo = EntitySchema( }, ); -export const Todo2 = EntitySchema( +export const Todo2 = Entity.Schema( { name: Type.String, checked: Type.Boolean, @@ -50,7 +50,7 @@ export const Todo2 = EntitySchema( }, ); -export const JobOffer = EntitySchema( +export const JobOffer = Entity.Schema( { name: Type.String, salary: Type.Number, @@ -64,7 +64,7 @@ export const JobOffer = EntitySchema( }, ); -export const Company = EntitySchema( +export const Company = Entity.Schema( { name: Type.String, jobOffers: Type.Relation(JobOffer), @@ -78,7 +78,7 @@ export const Company = EntitySchema( }, ); -export const Event = EntitySchema( +export const Event = Entity.Schema( { name: Type.String, description: Type.optional(Type.String), @@ -94,7 +94,7 @@ export const Event = EntitySchema( }, ); -export const Image = EntitySchema( +export const Image = Entity.Schema( { url: Type.String, }, @@ -106,7 +106,7 @@ export const Image = EntitySchema( }, ); -export const Project = EntitySchema( +export const Project = Entity.Schema( { name: Type.String, description: Type.optional(Type.String), diff --git a/apps/template-nextjs/app/schema.ts b/apps/template-nextjs/app/schema.ts index fad1102e..b658fe77 100644 --- a/apps/template-nextjs/app/schema.ts +++ b/apps/template-nextjs/app/schema.ts @@ -1,6 +1,6 @@ -import { EntitySchema, Id, Type } from '@graphprotocol/hypergraph'; +import { Entity, Id, Type } from '@graphprotocol/hypergraph'; -export const Image = EntitySchema( +export const Image = Entity.Schema( { url: Type.String, }, @@ -12,7 +12,7 @@ export const Image = EntitySchema( }, ); -export const Project = EntitySchema( +export const Project = Entity.Schema( { name: Type.String, description: Type.optional(Type.String), @@ -30,7 +30,7 @@ export const Project = EntitySchema( }, ); -export const Dapp = EntitySchema( +export const Dapp = Entity.Schema( { name: Type.String, description: Type.optional(Type.String), @@ -50,7 +50,7 @@ export const Dapp = EntitySchema( }, ); -export const Investor = EntitySchema( +export const Investor = Entity.Schema( { name: Type.String, }, @@ -62,7 +62,7 @@ export const Investor = EntitySchema( }, ); -export const FundingStage = EntitySchema( +export const FundingStage = Entity.Schema( { name: Type.String, }, @@ -74,7 +74,7 @@ export const FundingStage = EntitySchema( }, ); -export const InvestmentRound = EntitySchema( +export const InvestmentRound = Entity.Schema( { name: Type.String, raisedAmount: Type.optional(Type.Number), @@ -94,7 +94,7 @@ export const InvestmentRound = EntitySchema( }, ); -export const Asset = EntitySchema( +export const Asset = Entity.Schema( { name: Type.String, symbol: Type.optional(Type.String), diff --git a/apps/template-vite-react/src/schema.ts b/apps/template-vite-react/src/schema.ts index fad1102e..b658fe77 100644 --- a/apps/template-vite-react/src/schema.ts +++ b/apps/template-vite-react/src/schema.ts @@ -1,6 +1,6 @@ -import { EntitySchema, Id, Type } from '@graphprotocol/hypergraph'; +import { Entity, Id, Type } from '@graphprotocol/hypergraph'; -export const Image = EntitySchema( +export const Image = Entity.Schema( { url: Type.String, }, @@ -12,7 +12,7 @@ export const Image = EntitySchema( }, ); -export const Project = EntitySchema( +export const Project = Entity.Schema( { name: Type.String, description: Type.optional(Type.String), @@ -30,7 +30,7 @@ export const Project = EntitySchema( }, ); -export const Dapp = EntitySchema( +export const Dapp = Entity.Schema( { name: Type.String, description: Type.optional(Type.String), @@ -50,7 +50,7 @@ export const Dapp = EntitySchema( }, ); -export const Investor = EntitySchema( +export const Investor = Entity.Schema( { name: Type.String, }, @@ -62,7 +62,7 @@ export const Investor = EntitySchema( }, ); -export const FundingStage = EntitySchema( +export const FundingStage = Entity.Schema( { name: Type.String, }, @@ -74,7 +74,7 @@ export const FundingStage = EntitySchema( }, ); -export const InvestmentRound = EntitySchema( +export const InvestmentRound = Entity.Schema( { name: Type.String, raisedAmount: Type.optional(Type.Number), @@ -94,7 +94,7 @@ export const InvestmentRound = EntitySchema( }, ); -export const Asset = EntitySchema( +export const Asset = Entity.Schema( { name: Type.String, symbol: Type.optional(Type.String), diff --git a/docs/docs/filtering-query-results.md b/docs/docs/filtering-query-results.md index 2754e0f3..0747a900 100644 --- a/docs/docs/filtering-query-results.md +++ b/docs/docs/filtering-query-results.md @@ -5,10 +5,13 @@ The filter API allows you to filter the results of a query by property values an ## Filtering by property values ```tsx -export class Event extends Entity.Class("Event")({ - name: Type.String, - cancelled: Type.Boolean, -}) {} +export const Event = Entity.Schema( + { name: Type.String, cancelled: Type.Boolean }, + { + types: [Id('event-type-id')], + properties: { name: Id('name-property-id'), cancelled: Id('cancelled-property-id') }, + }, +); // inside the React component const { data } = useEntities(Event, { @@ -128,11 +131,17 @@ const { data } = useEntities(Person, { ```tsx // schema -export class Todo extends Entity.Class('Todo')({ - name: Type.String, - checked: Type.Boolean, - assignees: Type.Relation(User), -}) +export const Todo = Entity.Schema( + { name: Type.String, checked: Type.Boolean, assignees: Type.Relation(User) }, + { + types: [Id('todo-type-id')], + properties: { + name: Id('name-property-id'), + checked: Id('checked-property-id'), + assignees: Id('assignees-property-id'), + }, + }, +); ``` 1 level filtering @@ -171,15 +180,17 @@ const { data } = useEntities(Person, { ```tsx // schema -export class Todo extends Entity.Class('Todo')({ - name: Type.String, - checked: Type.Boolean, - assignees: Type.Relation(User, { - entity: { - assignedAt: Type.DateTime, - } - }), -}) +export const Todo = Entity.Schema( + { name: Type.String, checked: Type.Boolean, assignees: Type.Relation(User) }, + { + types: [Id('todo-type-id')], + properties: { + name: Id('name-property-id'), + checked: Id('checked-property-id'), + assignees: Id('assignees-property-id'), + }, + }, +); ``` ```tsx diff --git a/docs/docs/mapping.md b/docs/docs/mapping.md deleted file mode 100644 index d49010d2..00000000 --- a/docs/docs/mapping.md +++ /dev/null @@ -1,41 +0,0 @@ -# Mapping - -The public knowledge graph is based on property IDs. In order to integrate with the public knowledge graph you need to map your own schema to IDs from the public graph's schema. - -This is done using an object called a mapping. The mapping has to be provided to the `HypergraphAppProvider` component. - -A mapping entry defines the type IDs, properties and relations of a type. Here is an example mapping for a schema with an `Event` and a `Company`: - -```tsx -export const mapping: Mapping = { - Event: { - typeIds: [Id('407d9e8a-c703-4fb4-830d-98c758c8564e')], - properties: { - name: Id('a126ca53-0c8e-48d5-b888-82c734c38935'), - }, - relations: { - sponsors: Id('a7ac80a6-d3d9-4b04-9b9f-ead1723af09f'), - }, - }, - Company: { - typeIds: [Id('b0220a78-9205-4e5e-9bf1-c03ee0791e23')], - properties: { - name: Id('a126ca53-0c8e-48d5-b888-82c734c38935'), - }, - }, -``` - -The entire mapping structure can be generated using the TypeSync tool. - -```bash -pnpm install -g @graphprotocol/hypergraph-cli@latest -hg typesync --open -``` - -## Mapping Examples - -You can search for dozens of schema/mapping examples on the [Hypergraph Schema Browser](https://schema-browser.vercel.app/). - -## Creating and publishing new Properties and Types - -We created a script to create and publish new properties and types to the public knowledge graph. You can find it at [https://github.com/geobrowser/create-types-and-properties](https://github.com/geobrowser/create-types-and-properties). \ No newline at end of file diff --git a/docs/docs/query-public-data.md b/docs/docs/query-public-data.md index 3f28bfd5..cde23408 100644 --- a/docs/docs/query-public-data.md +++ b/docs/docs/query-public-data.md @@ -69,7 +69,7 @@ The Geo testnet contains public data that you can query immediately without any - **No authentication required** for public data queries. - All examples below use the Geo testnet space ID: `3f32353d-3b27-4a13-b71a-746f06e1f7db` -Each section below includes the relevant `schema.ts`, `mapping.ts`, and a query example. +Each section below includes the relevant `schema.ts` and a query example. ### Projects Example @@ -77,32 +77,19 @@ Each section below includes the relevant `schema.ts`, `mapping.ts`, and a query ```typescript // app/schema.ts -import { Entity, Type } from "@graphprotocol/hypergraph"; - -export class Project extends Entity.Class("Project")({ - name: Type.String, - description: Type.optional(Type.String), - xUrl: Type.optional(Type.String), -}) {} -``` - -**Mapping Definition:** +import { Entity, Type, Id } from "@graphprotocol/hypergraph"; -```typescript -// app/mapping.ts -import type { Mapping } from '@graphprotocol/hypergraph'; -import { Id } from '@graphprotocol/hypergraph'; - -export const mapping: Mapping.Mapping = { - Project: { - typeIds: [Id('484a18c5-030a-499c-b0f2-ef588ff16d50')], +export const Project = Entity.Schema( + { name: Type.String, description: Type.optional(Type.String), xUrl: Type.optional(Type.String) }, + { + types: [Id('484a18c5-030a-499c-b0f2-ef588ff16d50')], properties: { name: Id('a126ca53-0c8e-48d5-b888-82c734c38935'), description: Id('9b1f76ff-9711-404c-861e-59dc3fa7d037'), x: Id('0d625978-4b3c-4b57-a86f-de45c997c73c'), }, }, -}; +); ``` **Query Example:** @@ -171,24 +158,10 @@ export default function ProjectsExample() { // app/schema.ts import { Entity, Type } from "@graphprotocol/hypergraph"; -export class Dapp extends Entity.Class("Dapp")({ - name: Type.String, - description: Type.optional(Type.String), - xUrl: Type.optional(Type.String), - githubUrl: Type.optional(Type.String), -}) {} -``` - -**Mapping Definition:** - -```typescript -// app/mapping.ts -import type { Mapping } from '@graphprotocol/hypergraph'; -import { Id } from '@graphprotocol/hypergraph'; - -export const mapping: Mapping.Mapping = { - Dapp: { - typeIds: [Id('8ca136d0-698a-4bbf-a76b-8e2741b2dc8c')], +export const Dapp = Entity.Schema( + { name: Type.String, description: Type.optional(Type.String), xUrl: Type.optional(Type.String), githubUrl: Type.optional(Type.String) }, + { + types: [Id('8ca136d0-698a-4bbf-a76b-8e2741b2dc8c')], properties: { name: Id('a126ca53-0c8e-48d5-b888-82c734c38935'), description: Id('9b1f76ff-9711-404c-861e-59dc3fa7d037'), @@ -196,7 +169,7 @@ export const mapping: Mapping.Mapping = { github: Id('9eedefa8-60ae-4ac1-9a04-805054a4b094'), }, }, -}; +); ``` **Query Example:** @@ -269,55 +242,43 @@ export default function DappsExample() { ```typescript // app/schema.ts -import { Entity, Type } from "@graphprotocol/hypergraph"; - -export class Investor extends Entity.Class("Investor")({ - name: Type.String, -}) {} - -export class FundingStage extends Entity.Class("FundingStage")({ - name: Type.String, -}) {} - -export class InvestmentRound extends Entity.Class( - "InvestmentRound" -)({ - name: Type.String, - raisedAmount: Type.optional(Type.Number), - investors: Type.Relation(Investor), - fundingStages: Type.Relation(FundingStage), -}) {} -``` +import { Entity, Type, Id } from "@graphprotocol/hypergraph"; -**Mapping Definition:** - -```typescript -// app/mapping.ts -import type { Mapping } from '@graphprotocol/hypergraph'; -import { Id } from '@graphprotocol/hypergraph'; - -export const mapping: Mapping.Mapping = { - Investor: { - typeIds: [Id('331aea18-973c-4adc-8f53-614f598d262d')], +export const Investor = Entity.Schema( + { name: Type.String }, + { + types: [Id('331aea18-973c-4adc-8f53-614f598d262d')], properties: { name: Id('a126ca53-0c8e-48d5-b888-82c734c38935') }, }, - FundingStage: { - typeIds: [Id('8d35d217-3fa1-4686-b74f-fcb3e9438067')], +); + +export const FundingStage = Entity.Schema( + { name: Type.String }, + { + types: [Id('8d35d217-3fa1-4686-b74f-fcb3e9438067')], properties: { name: Id('a126ca53-0c8e-48d5-b888-82c734c38935') }, }, - InvestmentRound: { - typeIds: [Id('8f03f4c9-59e4-44a8-a625-c0a40b1ff330')], +); + +export const InvestmentRound = Entity.Schema( + { + name: Type.String, + raisedAmount: Type.optional(Type.Number), + investors: Type.Relation(Investor), + fundingStages: Type.Relation(FundingStage), + raisedBy: Type.Relation(Project), + }, + { + types: [Id('8f03f4c9-59e4-44a8-a625-c0a40b1ff330')], properties: { name: Id('a126ca53-0c8e-48d5-b888-82c734c38935'), raisedAmount: Id('16781706-dd9c-48bf-913e-cdf18b56034f'), - }, - relations: { investors: Id('9b8a610a-fa35-486e-a479-e253dbdabb4f'), fundingStages: Id('e278c3d4-78b9-4222-b272-5a39a8556bd2'), raisedBy: Id('b4878d1a-0609-488d-b8a6-e19862d6b62f'), }, }, -}; +); ``` **Query Example:** @@ -402,33 +363,19 @@ export default function InvestmentRoundsExample() { ```typescript // app/schema.ts -import { Entity, Type } from "@graphprotocol/hypergraph"; +import { Entity, Type, Id } from "@graphprotocol/hypergraph"; -export class Asset extends Entity.Class("Asset")({ - name: Type.String, - symbol: Type.optional(Type.String), - blockchainAddress: Type.optional(Type.String), -}) {} -``` - -**Mapping Definition:** - -```typescript -// app/mapping.ts -import type { Mapping } from '@graphprotocol/hypergraph'; -import { Id } from '@graphprotocol/hypergraph'; - -export const mapping: Mapping.Mapping = { - Asset: { - typeIds: [Id('f8780a80-c238-4a2a-96cb-567d88b1aa63')], +export const Asset = Entity.Schema( + { name: Type.String, symbol: Type.optional(Type.String), blockchainAddress: Type.optional(Type.String) }, + { + types: [Id('f8780a80-c238-4a2a-96cb-567d88b1aa63')], properties: { name: Id('a126ca53-0c8e-48d5-b888-82c734c38935'), symbol: Id('ace1e96c-9b83-47b4-bd33-1d302ec0a0f5'), blockchainAddress: Id('56b5944f-f059-48d1-b0fa-34abe84219da'), }, }, -}; - +); ``` **Query Example:** diff --git a/docs/docs/schema.md b/docs/docs/schema.md index d6358543..2fab9cf3 100644 --- a/docs/docs/schema.md +++ b/docs/docs/schema.md @@ -2,23 +2,38 @@ The Hypergraph schema allows you to define the data model for your application. It is based on the GRC-20 specification and allows you to define Types with properties and relations to other Types. +## Mapping + +The public knowledge graph is based on property IDs. In order to integrate with the public knowledge graph you need to map your own schema to IDs from the public graph's schema. Until you interact with the public knowledge graph or before publishing your schema to the public knowledge graph you can use any valid UUID as a property ID. + ## Hypergraph Schema Browser Building your app using a schema that is already actively used in Hypergraph's knowledge graph unlocks composability between your dataset and other datasets used in Hypergraph's knowledge graph. -You can search for schemas used within the Hypergraph knowledge graph using the [Hypergraph Schema Browser](https://schema-browser.vercel.app/). +You can search for schemas used within the Hypergraph knowledge graph using the [Hypergraph Schema Browser](https://schema-browser.vercel.app/). You can also use the TypeSync tool to generate a mapping for your schema. + +**Warning:** TypeSync is not supported in the latest version of the `hypergraph` package. We are working on a new version of TypeSync. ## Example Here is an example of a schema for an Event entity with the properties `name` and `description`. ```ts -import { Entity, Type } from '@graphprotocol/hypergraph'; - -export class Event extends Entity.Class('Event')({ - name: Type.String, - description: Type.String, -}) {} +import { Entity, Type, Id } from '@graphprotocol/hypergraph'; + +export const Event = Entity.Schema( + { + name: Type.String, + description: Type.String, + }, + { + types: [Id('event-type-id')], + properties: { + name: Id('name-property-id'), + description: Id('description-property-id'), + }, + }, +); ``` ## Relations @@ -26,17 +41,32 @@ export class Event extends Entity.Class('Event')({ In order to define relations between Types, you can use the `Type.Relation` type. ```ts -import { Entity, Type } from '@graphprotocol/hypergraph'; - -export class Company extends Entity.Class('Company')({ - name: Type.String, -}) {} - -export class Event extends Entity.Class('Event')({ - name: Type.String, - description: Type.String, - sponsors: Type.Relation(Company), -}) {} +import { Entity, Type, Id } from '@graphprotocol/hypergraph'; + +export const Company = Entity.Schema( + { name: Type.String }, + { + types: [Id('company-type-id')], + properties: { + name: Id('name-property-id'), + }, + }, +); + +export const Event = Entity.Schema( + { + name: Type.String, + description: Type.String, + }, + { + types: [Id('event-type-id')], + properties: { + name: Id('name-property-id'), + description: Id('description-property-id'), + sponsors: Id('sponsors-property-id'), + }, + }, +); ``` ## Available Types @@ -51,15 +81,27 @@ export class Event extends Entity.Class('Event')({ Example: ```ts -import { Entity, Type } from '@graphprotocol/hypergraph'; - -export class Company extends Entity.Class('Company')({ - name: Type.String, - employees: Type.Number, - founded: Type.Date, - active: Type.Boolean, - location: Type.Point, -}) {} +import { Entity, Type, Id } from '@graphprotocol/hypergraph'; + +export const Company = Entity.Schema( + { + name: Type.String, + employees: Type.Number, + founded: Type.Date, + active: Type.Boolean, + location: Type.Point, + }, + { + types: [Id('company-type-id')], + properties: { + name: Id('name-property-id'), + employees: Id('employees-property-id'), + founded: Id('founded-property-id'), + active: Id('active-property-id'), + location: Id('location-property-id'), + }, + }, +); ``` ## Optional Fields @@ -67,11 +109,25 @@ export class Company extends Entity.Class('Company')({ You can make a field optional by wrapping it in `Type.optional`. ```ts -import { Entity, Type } from '@graphprotocol/hypergraph'; +import { Entity, Type, Id } from '@graphprotocol/hypergraph'; -export class Company extends Entity.Class('Company')({ +export const Company = Entity.Schema( + { name: Type.String, description: Type.optional(Type.String), founded: Type.optional(Type.Date), -}) {} + }, + { + types: [Id('company-type-id')], + properties: { + name: Id('name-property-id'), + description: Id('description-property-id'), + founded: Id('founded-property-id'), + }, + }, +); ``` + +## Creating and publishing new Properties and Types + +We created a script to create and publish new properties and types to the public knowledge graph. You can find it at [https://github.com/geobrowser/create-types-and-properties](https://github.com/geobrowser/create-types-and-properties). \ No newline at end of file diff --git a/docs/docs/typesync.md b/docs/docs/typesync.md index 2172377d..e1429127 100644 --- a/docs/docs/typesync.md +++ b/docs/docs/typesync.md @@ -7,6 +7,8 @@ tags: [typesync, hypergraph-cli, schema] # 🧬 TypeSync +**WARNING: This tool is currently not supported in the latest version of the `hypergraph` package. We are working on a new version of TypeSync.** + TypeSync is a visual tool that helps you manage your Hypergraph schema and update the schema.ts and mapping.ts for your Hypergraph application. ## Installation diff --git a/docs/sidebars.js b/docs/sidebars.js index 07b8682c..b7d5609c 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -31,7 +31,6 @@ const sidebars = { { type: 'doc', id: 'schema', label: '🔗 Schema' }, { type: 'doc', id: 'writing-private-data', label: '✍️ Writing Private Data' }, { type: 'doc', id: 'query-private-data', label: '🔍 Query Private Data' }, - { type: 'doc', id: 'mapping', label: '🔗 Mapping' }, { type: 'doc', id: 'publishing-public-data', label: '✍️ Publishing Public Data' }, { type: 'doc', id: 'query-public-data', label: '🔍 Query Public Data' }, { type: 'doc', id: 'filtering-query-results', label: '🔍 Filtering Query Results' }, diff --git a/packages/hypergraph-react/test/HypergraphSpaceContext.test.tsx b/packages/hypergraph-react/test/HypergraphSpaceContext.test.tsx index 53d5c3e2..83dace06 100644 --- a/packages/hypergraph-react/test/HypergraphSpaceContext.test.tsx +++ b/packages/hypergraph-react/test/HypergraphSpaceContext.test.tsx @@ -1,6 +1,6 @@ import { Repo } from '@automerge/automerge-repo'; import { RepoContext } from '@automerge/automerge-repo-react-hooks'; -import { type Entity, EntitySchema, Id, store, Type } from '@graphprotocol/hypergraph'; +import { Entity, Id, store, Type } from '@graphprotocol/hypergraph'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import '@testing-library/jest-dom/vitest'; import { act, cleanup, renderHook, waitFor } from '@testing-library/react'; @@ -18,7 +18,7 @@ afterEach(() => { }); describe('HypergraphSpaceContext', () => { - const Person = EntitySchema( + const Person = Entity.Schema( { name: Type.String, age: Type.Number, @@ -32,7 +32,7 @@ describe('HypergraphSpaceContext', () => { }, ); - const User = EntitySchema( + const User = Entity.Schema( { name: Type.String, email: Type.String, @@ -46,7 +46,7 @@ describe('HypergraphSpaceContext', () => { }, ); - const Event = EntitySchema( + const Event = Entity.Schema( { name: Type.String, }, diff --git a/packages/hypergraph-react/test/internal/translate-filter-to-graphql.test.ts b/packages/hypergraph-react/test/internal/translate-filter-to-graphql.test.ts index f9c3b512..22fe1da3 100644 --- a/packages/hypergraph-react/test/internal/translate-filter-to-graphql.test.ts +++ b/packages/hypergraph-react/test/internal/translate-filter-to-graphql.test.ts @@ -1,10 +1,10 @@ import { Graph, Id } from '@graphprotocol/grc-20'; -import { type Entity, EntitySchema, Type } from '@graphprotocol/hypergraph'; +import { Entity, Type } from '@graphprotocol/hypergraph'; import type * as Schema from 'effect/Schema'; import { describe, expect, it } from 'vitest'; import { translateFilterToGraphql } from '../../src/internal/translate-filter-to-graphql.js'; -export const Todo = EntitySchema( +export const Todo = Entity.Schema( { name: Type.String, completed: Type.Boolean, diff --git a/packages/hypergraph-react/test/prepare-publish.test.ts b/packages/hypergraph-react/test/prepare-publish.test.ts index 9f6bc1b3..8b85a2ac 100644 --- a/packages/hypergraph-react/test/prepare-publish.test.ts +++ b/packages/hypergraph-react/test/prepare-publish.test.ts @@ -1,6 +1,6 @@ import { Repo } from '@automerge/automerge-repo'; import { Graph, Id } from '@graphprotocol/grc-20'; -import { type Entity, EntitySchema, store, Type } from '@graphprotocol/hypergraph'; +import { Entity, store, Type } from '@graphprotocol/hypergraph'; import '@testing-library/jest-dom/vitest'; import request from 'graphql-request'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; @@ -20,7 +20,7 @@ afterEach(() => { describe('preparePublish', () => { // Test entity classes - const Person = EntitySchema( + const Person = Entity.Schema( { name: Type.String, age: Type.Number, @@ -42,7 +42,7 @@ describe('preparePublish', () => { }, ); - const Company = EntitySchema( + const Company = Entity.Schema( { name: Type.String, employees: Type.Relation(Person), @@ -57,7 +57,7 @@ describe('preparePublish', () => { ); // Entity class for testing optional types - const OptionalFieldsEntity = EntitySchema( + const OptionalFieldsEntity = Entity.Schema( { name: Type.String, // required field optionalNumber: Type.optional(Type.Number), diff --git a/packages/hypergraph/src/entity/create.ts b/packages/hypergraph/src/entity/create.ts index 4a6de08f..3571264d 100644 --- a/packages/hypergraph/src/entity/create.ts +++ b/packages/hypergraph/src/entity/create.ts @@ -5,8 +5,8 @@ import * as SchemaAST from 'effect/SchemaAST'; import { PropertyIdSymbol } from '../constants.js'; import { generateId } from '../utils/generateId.js'; import { isRelation } from '../utils/isRelation.js'; -import { encodeToGrc20Json } from './entity.js'; import { findOne } from './findOne.js'; +import { encodeToGrc20Json } from './schema.js'; import type { DocumentContent, DocumentRelation, Entity } from './types.js'; /** @@ -14,16 +14,17 @@ import type { DocumentContent, DocumentRelation, Entity } from './types.js'; * This specifically targets Type.Relation fields which are arrays of objects. */ type RelationArrayKeys = { - [K in keyof T]: T[K] extends readonly (infer U)[] - ? U extends object - ? K + // For each property K in T, check if it's an array of objects (relation fields) + [K in keyof T]: T[K] extends readonly (infer U)[] // Check for readonly arrays + ? U extends object // If array element is an object + ? K // Return the property key K : never - : T[K] extends (infer U)[] - ? U extends object - ? K + : T[K] extends (infer U)[] // Check for mutable arrays + ? U extends object // If array element is an object + ? K // Return the property key K : never - : never; -}[keyof T]; + : never; // Not an array of objects, so exclude +}[keyof T]; // Extract the union of all matching property keys type WithRelationsAsStringArrays = Omit> & Partial, string[] | undefined>>; diff --git a/packages/hypergraph/src/entity/findMany.ts b/packages/hypergraph/src/entity/findMany.ts index 934a5b72..66a4073f 100644 --- a/packages/hypergraph/src/entity/findMany.ts +++ b/packages/hypergraph/src/entity/findMany.ts @@ -6,10 +6,10 @@ import { TypeIdsSymbol } from '../constants.js'; import { deepMerge } from '../utils/internal/deep-merge.js'; import { canonicalize } from '../utils/jsc.js'; import { type DecodedEntitiesCacheEntry, decodedEntitiesCache, type QueryEntry } from './decodedEntitiesCache.js'; -import { decodeFromGrc20Json } from './entity.js'; import { entityRelationParentsMap } from './entityRelationParentsMap.js'; import { getEntityRelations } from './getEntityRelations.js'; import { hasValidTypesProperty } from './hasValidTypesProperty.js'; +import { decodeFromGrc20Json } from './schema.js'; import type { CrossFieldFilter, DocumentContent, diff --git a/packages/hypergraph/src/entity/findOne.ts b/packages/hypergraph/src/entity/findOne.ts index 45f5288c..b256a4b9 100644 --- a/packages/hypergraph/src/entity/findOne.ts +++ b/packages/hypergraph/src/entity/findOne.ts @@ -3,9 +3,9 @@ import * as Option from 'effect/Option'; import type * as Schema from 'effect/Schema'; import * as SchemaAST from 'effect/SchemaAST'; import { TypeIdsSymbol } from '../constants.js'; -import { decodeFromGrc20Json } from './entity.js'; import { getEntityRelations } from './getEntityRelations.js'; import { hasValidTypesProperty } from './hasValidTypesProperty.js'; +import { decodeFromGrc20Json } from './schema.js'; import type { DocumentContent, Entity } from './types.js'; export const findOne = ( diff --git a/packages/hypergraph/src/entity/getEntityRelations.ts b/packages/hypergraph/src/entity/getEntityRelations.ts index 0cf14059..412a7949 100644 --- a/packages/hypergraph/src/entity/getEntityRelations.ts +++ b/packages/hypergraph/src/entity/getEntityRelations.ts @@ -3,8 +3,8 @@ import type * as Schema from 'effect/Schema'; import * as SchemaAST from 'effect/SchemaAST'; import { PropertyIdSymbol, RelationSchemaSymbol } from '../constants.js'; import { isRelation } from '../utils/isRelation.js'; -import { decodeFromGrc20Json } from './entity.js'; import { hasValidTypesProperty } from './hasValidTypesProperty.js'; +import { decodeFromGrc20Json } from './schema.js'; import type { DocumentContent, Entity } from './types.js'; export const getEntityRelations = ( diff --git a/packages/hypergraph/src/entity/index.ts b/packages/hypergraph/src/entity/index.ts index 7db90700..0470f664 100644 --- a/packages/hypergraph/src/entity/index.ts +++ b/packages/hypergraph/src/entity/index.ts @@ -3,5 +3,6 @@ export * from './delete.js'; export * from './findMany.js'; export * from './findOne.js'; export * from './removeRelation.js'; +export * from './schema.js'; export * from './types.js'; export * from './update.js'; diff --git a/packages/hypergraph/src/entity/entity.ts b/packages/hypergraph/src/entity/schema.ts similarity index 76% rename from packages/hypergraph/src/entity/entity.ts rename to packages/hypergraph/src/entity/schema.ts index 03011f53..ded3d400 100644 --- a/packages/hypergraph/src/entity/entity.ts +++ b/packages/hypergraph/src/entity/schema.ts @@ -1,6 +1,6 @@ import * as Data from 'effect/Data'; import * as Option from 'effect/Option'; -import * as Schema from 'effect/Schema'; +import * as EffectSchema from 'effect/Schema'; import * as SchemaAST from 'effect/SchemaAST'; import { PropertyIdSymbol, TypeIdsSymbol } from '../constants.js'; @@ -10,20 +10,20 @@ import { PropertyIdSymbol, TypeIdsSymbol } from '../constants.js'; * * @example * ```typescript - * const User = EntityDefinition({ + * const User = Entity.Schema({ * name: Type.String, * age: Type.Number, * }, { - * name: "grc-20-name", - * age: "grc-20-age" + * name: "grc-20-id", + * age: "grc-20-id" * }); * ``` */ -export function EntitySchema< +export function Schema< T extends Record< string, // biome-ignore lint/suspicious/noExplicitAny: any - (propertyId: string) => Schema.Schema | Schema.PropertySignature + (propertyId: string) => EffectSchema.Schema | EffectSchema.PropertySignature >, P extends Record, >( @@ -32,12 +32,14 @@ export function EntitySchema< types: Array; properties: P; }, -): Schema.Struct<{ +): EffectSchema.Struct<{ [K in keyof T]: ReturnType & { id: string }; }> { - // biome-ignore lint/suspicious/noExplicitAny: any - const properties: Record | Schema.PropertySignature> = - {}; + const properties: Record< + string, + // biome-ignore lint/suspicious/noExplicitAny: any + EffectSchema.Schema | EffectSchema.PropertySignature + > = {}; for (const [key, schemaType] of Object.entries(schemaTypes)) { const propertyId = mapping.properties[key as keyof P]; @@ -45,10 +47,13 @@ export function EntitySchema< } // biome-ignore lint/suspicious/noExplicitAny: any - return Schema.Struct(properties).pipe(Schema.annotations({ [TypeIdsSymbol]: mapping.types })) as any; + return EffectSchema.Struct(properties).pipe(EffectSchema.annotations({ [TypeIdsSymbol]: mapping.types })) as any; } -export function encodeToGrc20Json(schema: Schema.Schema, value: T): Record { +export function encodeToGrc20Json( + schema: EffectSchema.Schema, + value: T, +): Record { const ast = schema.ast as SchemaAST.TypeLiteral; const out: Record = {}; @@ -72,7 +77,7 @@ export function encodeToGrc20Json(schema: Schema.Schema( - schema: Schema.Schema, + schema: EffectSchema.Schema, grc20Data: Record, ): T { const ast = schema.ast as SchemaAST.TypeLiteral; @@ -101,6 +106,6 @@ export function decodeFromGrc20Json( export class EntityNotFoundError extends Data.TaggedError('EntityNotFoundError')<{ id: string; - type: Schema.Schema.AnyNoContext; + type: EffectSchema.Schema.AnyNoContext; cause?: unknown; }> {} diff --git a/packages/hypergraph/src/entity/update.ts b/packages/hypergraph/src/entity/update.ts index 81bdaf21..31fff30b 100644 --- a/packages/hypergraph/src/entity/update.ts +++ b/packages/hypergraph/src/entity/update.ts @@ -1,7 +1,7 @@ import type { DocHandle } from '@automerge/automerge-repo'; import * as Schema from 'effect/Schema'; -import { decodeFromGrc20Json, EntityNotFoundError, encodeToGrc20Json } from './entity.js'; import { findOne } from './findOne.js'; +import { decodeFromGrc20Json, EntityNotFoundError, encodeToGrc20Json } from './schema.js'; import type { DocumentContent, DocumentEntity, Entity } from './types.js'; /** diff --git a/packages/hypergraph/src/index.ts b/packages/hypergraph/src/index.ts index 80579812..f88b0ab8 100644 --- a/packages/hypergraph/src/index.ts +++ b/packages/hypergraph/src/index.ts @@ -2,7 +2,6 @@ export { Id } from '@graphprotocol/grc-20'; export * as Typesync from './cli/services/Model.js'; export * as Connect from './connect/index.js'; export * as Constants from './constants.js'; -export { EntitySchema } from './entity/entity.js'; export * as Entity from './entity/index.js'; export * as Identity from './identity/index.js'; export * as Inboxes from './inboxes/index.js'; diff --git a/packages/hypergraph/test/entity/entity.test.ts b/packages/hypergraph/test/entity/entity.test.ts index 216320bb..235a3b2d 100644 --- a/packages/hypergraph/test/entity/entity.test.ts +++ b/packages/hypergraph/test/entity/entity.test.ts @@ -2,13 +2,12 @@ import type { AnyDocumentId, DocHandle } from '@automerge/automerge-repo'; import { Repo } from '@automerge/automerge-repo'; import { Id } from '@graphprotocol/grc-20'; import { beforeEach, describe, expect, it } from 'vitest'; -import { EntitySchema } from '../../src/entity/entity.js'; import * as Entity from '../../src/entity/index.js'; import * as Type from '../../src/type/type.js'; import { idToAutomergeId } from '../../src/utils/automergeId.js'; describe('Entity', () => { - const Person = EntitySchema( + const Person = Entity.Schema( { name: Type.String, age: Type.Number, @@ -22,7 +21,7 @@ describe('Entity', () => { }, ); - const User = EntitySchema( + const User = Entity.Schema( { name: Type.String, email: Type.String, @@ -36,7 +35,7 @@ describe('Entity', () => { }, ); - const Badge = EntitySchema( + const Badge = Entity.Schema( { name: Type.String, }, @@ -48,7 +47,7 @@ describe('Entity', () => { }, ); - const Event = EntitySchema( + const Event = Entity.Schema( { name: Type.String, }, diff --git a/packages/hypergraph/test/entity/findMany.test.ts b/packages/hypergraph/test/entity/findMany.test.ts index 4e7ff4b4..b4ec740d 100644 --- a/packages/hypergraph/test/entity/findMany.test.ts +++ b/packages/hypergraph/test/entity/findMany.test.ts @@ -2,7 +2,6 @@ import type { AnyDocumentId, DocHandle } from '@automerge/automerge-repo'; import { Repo } from '@automerge/automerge-repo'; import { Id } from '@graphprotocol/grc-20'; import { beforeEach, describe, expect, it } from 'vitest'; -import { EntitySchema } from '../../src/entity/entity.js'; import * as Entity from '../../src/entity/index.js'; import * as Type from '../../src/type/type.js'; import { idToAutomergeId } from '../../src/utils/automergeId.js'; @@ -10,7 +9,7 @@ import { idToAutomergeId } from '../../src/utils/automergeId.js'; describe('findMany with filters', () => { // Define entity classes for testing - const Person = EntitySchema( + const Person = Entity.Schema( { name: Type.String, age: Type.Number, @@ -26,7 +25,7 @@ describe('findMany with filters', () => { }, ); - const Product = EntitySchema( + const Product = Entity.Schema( { name: Type.String, price: Type.Number,