# GraphQL Schema Reader The GraphQL reader parses GraphQL Schema Definition Language (SDL) files and converts them into RelSpec's internal database model. ## Features - **Standard GraphQL SDL** support (generic, non-framework-specific) - **Type to Table mapping**: GraphQL types become database tables - **Field to Column mapping**: GraphQL fields become table columns - **Enum support**: GraphQL enums are preserved - **Custom scalars**: DateTime, JSON, Date automatically mapped to appropriate SQL types - **Implicit relationships**: Detects relationships from field types - **Many-to-many support**: Creates junction tables for bidirectional array relationships - **Configurable ID mapping**: Choose between bigint (default) or UUID for ID fields ## Supported GraphQL Features ### Built-in Scalars - `ID` → bigint (default) or uuid (configurable) - `String` → text - `Int` → integer - `Float` → double precision - `Boolean` → boolean ### Custom Scalars - `DateTime` → timestamp - `JSON` → jsonb - `Date` → date - `Time` → time - `Decimal` → numeric Additional custom scalars can be mapped via metadata. ### Relationships Relationships are inferred from field types: ```graphql type Post { id: ID! title: String! author: User! # Many-to-one (creates authorId FK column, NOT NULL) reviewer: User # Many-to-one nullable (creates reviewerId FK column, NULL) tags: [Tag!]! # One-to-many or many-to-many (depending on reverse) } type User { id: ID! posts: [Post!]! # Reverse of Post.author (no FK created) } type Tag { id: ID! posts: [Post!]! # Many-to-many with Post (creates PostTag junction table) } ``` **Relationship Detection Rules:** - Single type reference (`user: User`) → Creates FK column (e.g., `userId`) - Array type reference (`posts: [Post!]!`) → One-to-many reverse (no FK on this table) - Bidirectional arrays → Many-to-many (creates junction table) ### Enums ```graphql enum Role { ADMIN USER GUEST } type User { role: Role! } ``` Enums are preserved in the schema and can be used as column types. ## Usage ### Basic Usage ```go import ( "git.warky.dev/wdevs/relspecgo/pkg/readers" "git.warky.dev/wdevs/relspecgo/pkg/readers/graphql" ) opts := &readers.ReaderOptions{ FilePath: "schema.graphql", } reader := graphql.NewReader(opts) db, err := reader.ReadDatabase() ``` ### With UUID ID Type ```go opts := &readers.ReaderOptions{ FilePath: "schema.graphql", Metadata: map[string]interface{}{ "idType": "uuid", // Map ID scalar to uuid instead of bigint }, } reader := graphql.NewReader(opts) db, err := reader.ReadDatabase() ``` ### With Per-Type ID Mapping ```go opts := &readers.ReaderOptions{ FilePath: "schema.graphql", Metadata: map[string]interface{}{ "typeIdMappings": map[string]string{ "User": "uuid", // User.id → uuid "Post": "bigint", // Post.id → bigint }, }, } ``` ### With Custom Scalar Mappings ```go opts := &readers.ReaderOptions{ FilePath: "schema.graphql", Metadata: map[string]interface{}{ "customScalarMappings": map[string]string{ "Upload": "bytea", "Decimal": "numeric(10,2)", }, }, } ``` ## CLI Usage ```bash # Convert GraphQL to JSON relspec convert --from graphql --from-path schema.graphql \ --to json --to-path schema.json # Convert GraphQL to GORM models relspec convert --from graphql --from-path schema.graphql \ --to gorm --to-path models/ --package models # Convert GraphQL to PostgreSQL SQL relspec convert --from graphql --from-path schema.graphql \ --to pgsql --to-path schema.sql ``` ## Metadata Options | Option | Type | Description | Default | |--------|------|-------------|---------| | `idType` | string | Global ID type mapping ("bigint" or "uuid") | "bigint" | | `typeIdMappings` | map[string]string | Per-type ID mappings | {} | | `customScalarMappings` | map[string]string | Custom scalar to SQL type mappings | {} | | `schemaName` | string | Schema name for all tables | "public" | ## Limitations - Only supports GraphQL SDL (Schema Definition Language), not queries or mutations - Directives are ignored (except for future extensibility) - Interfaces and Unions are not supported - GraphQL's concept of "schema" is different from database schemas; all types go into a single database schema (default: "public") ## Example **Input** (`schema.graphql`): ```graphql scalar DateTime enum Role { ADMIN USER } type User { id: ID! email: String! role: Role! createdAt: DateTime! posts: [Post!]! } type Post { id: ID! title: String! content: String published: Boolean! author: User! } ``` **Result**: Database with: - 2 tables: `User` and `Post` - `Post` table has `authorId` foreign key to `User.id` - `Role` enum with values: ADMIN, USER - Custom scalar `DateTime` mapped to `timestamp`