packages/sql-catalog/src/Core/Extension/Model/ModelSet.php

1<?php
2
3declare(strict_types=1);
4
5namespace SqlCatalog\Core\Extension\Model;
6
7use Closure;
8use SqlCatalog\Core\Evaluation\Domain;
9
10/**
11 * Call transformations, statement compilers and type relations registered by enabled extensions.
12 *
13 * @visibility public
14 *
15 * @example Registering a function that returns a SQL fragment
16 *     $models = new \SqlCatalog\Core\Extension\Model\ModelSet(calls: [
17 *         static fn (\SqlCatalog\Core\Extension\Model\CallContext $call): ?\SqlCatalog\Core\Evaluation\Domain =>
18 *             $call->name === 'today_sql' ? \SqlCatalog\Core\Evaluation\Domain::literal('CURRENT_DATE') : null,
19 *     ]);
20 *     count($models->calls) // => 1
21 */
22final class ModelSet
23{
24    /**
25     * @param list<Closure(CallContext): ?Domain> $calls Registered with the shared function-model registry; later registrations take priority.
26     * @param array<string, QueryModelInterface> $queries Statement models keyed by SinkSpec::model.
27     * @param list<Closure(string, string): bool> $classRelations Additional known subtype relations.
28     */
29    public function __construct(public readonly array $calls = [], public readonly array $queries = [], public readonly array $classRelations = [])
30    {
31    }
32
33    /**
34     * Combines registrations in extension order; later statement keys replace earlier ones.
35     */
36    public function merge(self $other): self
37    {
38        return new self(array_merge($this->calls, $other->calls), array_merge($this->queries, $other->queries), array_merge($this->classRelations, $other->classRelations));
39    }
40
41    /**
42     * Whether an extension declares a subtype relation absent from application source.
43     */
44    public function matchesClass(string $class, string $expected): bool
45    {
46        foreach ($this->classRelations as $relation) {
47            if ($relation($class, $expected)) {
48                return true;
49            }
50        }
51
52        return false;
53    }
54}
55