packages/sql-semantics/src/Core/Schema/TableConstraint.php
1<?php
2
3declare(strict_types=1);
4
5namespace SqlSemantics\Core\Schema;
6
7use InvalidArgumentException;
8use SqlSemantics\Statement\Element;
9
10/**
11 * A declared integrity condition, retaining its complete syntax for downstream consumers.
12 *
13 * @example Accept this semantic value in a database-independent consumer
14 * $consume = static fn (\SqlSemantics\Core\Schema\TableConstraint $value): string => $value::class;
15 * $consume instanceof \Closure // => true
16 *
17 * @visibility public
18 */
19final class TableConstraint
20{
21 /**
22 * @param ConstraintKind $kind Integrity condition
23 * @param list<string> $columns Local columns, in declaration order
24 * @param Element $source Typed constraint declaration, including actions and deferrability
25 * @param string|null $name Explicit constraint name
26 * @param list<string> $referencedTable Qualified foreign table name
27 * @param list<string> $referencedColumns Referenced key columns; empty means the primary key
28 * @param Element|null $expression Typed CHECK expression
29 * @throws InvalidArgumentException When supplied state violates its invariants
30 */
31 public function __construct(
32 public readonly ConstraintKind $kind,
33 public readonly array $columns,
34 public readonly Element $source,
35 public readonly ?string $name = null,
36 public readonly array $referencedTable = [],
37 public readonly array $referencedColumns = [],
38 public readonly ?Element $expression = null,
39 public readonly bool $inline = false,
40 public readonly bool $descending = false,
41 ) {
42 Invariant::names($columns);
43 Invariant::names($referencedTable);
44 Invariant::names($referencedColumns);
45 Invariant::elements($source, $expression);
46 Invariant::ensure(($kind === ConstraintKind::Check) === ($expression !== null), 'Only a CHECK constraint carries a predicate.');
47 Invariant::ensure($kind === ConstraintKind::ForeignKey || ($referencedTable === [] && $referencedColumns === []), 'Only foreign keys carry a reference.');
48 Invariant::ensure($kind !== ConstraintKind::ForeignKey || $referencedTable !== [], 'A foreign key needs a referenced table.');
49 }
50}
51