# 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`
