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

Validates that Postgres tables include required columns.

## Examples

With `rules: [[only: [schema: "public"], columns: ["tenant_id"]]]`, before:

```sql
CREATE TABLE invoices (
  id uuid PRIMARY KEY,
  amount numeric NOT NULL
);
```

Tables without the project-standard scope column are easy to query or mutate
without tenant filtering.

After, add the required column:

```sql
CREATE TABLE invoices (
  id uuid PRIMARY KEY,
  tenant_id uuid NOT NULL,
  amount numeric NOT NULL
);
```

The table can participate in the same scoping, authorization, and cleanup
patterns as the rest of the schema.

## Notes

The check only verifies column presence. It does not validate type,
nullability, indexes, or constraints for required columns.

## Options

Use `rules: [...]` to require columns for scoped groups of tables. A rule
applies when a table matches any matcher in `only`; keys inside one matcher
are combined. Matching rules accumulate, so the same table can be validated by
more than one rule.

```elixir
{Bylaw.Db.Adapters.Postgres.Checks.RequiredColumns,
 rules: [
   [
     columns: ["inserted_at", "updated_at"],
     except: [[table: "schema_migrations"]]
   ],
   [
     only: [
       [schema: "audit"],
       [schema: "billing", table: ~r/^invoice_/]
     ],
     columns: ["tenant_id"]
   ]
 ]}
```

Use rule-level `except: [...]` for exclusions.

## 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, [rule()]}
  | {:except, matcher() | [matcher()]}
```

# `check_opts`

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

# `matcher`

```elixir
@type matcher() :: [schema: matcher_values(), table: 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() :: %{
  columns: [String.t()],
  only: [matcher()],
  except: [matcher()]
}
```

# `rule`

```elixir
@type rule() :: [
  columns: [String.t()],
  only: matcher() | [matcher()],
  except: matcher() | [matcher()]
]
```

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