# `Bylaw.Db.Adapters.Postgres.Checks.ForbiddenColumnTypes`
[🔗](https://github.com/ryanzidago/bylaw/blob/v0.1.0-alpha.1/lib/bylaw/db/adapters/postgres/checks/forbidden_column_types.ex#L1)

Validates that Postgres columns do not use configured forbidden types.

## Examples

With `types: [[type: "json", prefer: "jsonb"]]`, before:

```sql
CREATE TABLE webhook_events (
  id uuid PRIMARY KEY,
  payload json NOT NULL
);
```

The project has decided this type is limiting or unsafe for its use case. For
example, plain `json` is less useful for common indexing and containment
queries than `jsonb`.

After, use the preferred type:

```sql
CREATE TABLE webhook_events (
  id uuid PRIMARY KEY,
  payload jsonb NOT NULL
);
```

The column now follows the project convention and avoids repeating the same
migration decision in future tables.

## Notes

This check is policy-driven and has no built-in opinion about which types are
bad. Type matchers compare against `pg_catalog.format_type`, so use exact
strings such as `"json"` or regexes such as `~r/^character\(/`.

## Options

By default the check inspects all non-system schemas in a Postgres target. Use
`rules: [...]` to configure forbidden types for scoped groups of columns:

```elixir
{Bylaw.Db.Adapters.Postgres.Checks.ForbiddenColumnTypes,
 rules: [
   [
     only: [schema: "public"],
     types: [
       [type: "json", prefer: "jsonb", reason: "jsonb supports common indexing patterns"],
       [type: ~r/^character\(/, prefer: "text"]
     ],
     except: [[table: "webhook_events", column: "raw_payload"]]
   ]
 ]}
```

## Usage

Add this module to the checks passed to
`Bylaw.Db.Adapters.Postgres.validate/2`. See the
[README usage section](readme.html#usage) for the full ExUnit setup.

# `check_opt`

```elixir
@type check_opt() :: {:validate, boolean()} | {:rules, [scope_rule()]}
```

# `check_opts`

```elixir
@type check_opts() :: [check_opt()]
```

# `matcher`

```elixir
@type matcher() :: [
  schema: matcher_values(),
  table: matcher_values(),
  column: matcher_values(),
  type: matcher_values()
]
```

# `matcher_value`

```elixir
@type matcher_value() :: String.t() | Regex.t()
```

# `matcher_values`

```elixir
@type matcher_values() :: matcher_value() | [matcher_value()]
```

# `normalized_rule`

```elixir
@type normalized_rule() :: %{
  type: type_matcher(),
  prefer: String.t() | nil,
  reason: String.t() | nil
}
```

# `scope_rule`

```elixir
@type scope_rule() :: [
  only: matcher() | [matcher()],
  except: matcher() | [matcher()],
  types: [type_rule()]
]
```

# `type_matcher`

```elixir
@type type_matcher() :: String.t() | Regex.t()
```

# `type_rule`

```elixir
@type type_rule() ::
  type_matcher()
  | [type: type_matcher(), prefer: String.t(), reason: String.t()]
```

# `validate`

```elixir
@spec validate(target :: Bylaw.Db.Target.t(), opts :: check_opts()) ::
  Bylaw.Db.Check.result()
```

Implements the `Bylaw.Db.Check` validation callback.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
