Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.22% covered (success)
97.22%
35 / 36
90.91% covered (success)
90.91%
10 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
Column
97.22% covered (success)
97.22%
35 / 36
90.91% covered (success)
90.91%
10 / 11
17
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 create
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __toString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 empty
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 fields
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 parse
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 matchField
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 createField
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
 transformAlias
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 buildAggregate
83.33% covered (warning)
83.33%
5 / 6
0.00% covered (danger)
0.00%
0 / 1
2.02
 buildField
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3declare(strict_types=1);
4
5namespace Projom\Storage\SQL\Component;
6
7use Projom\Storage\SQL\Component\ComponentInterface;
8use Projom\Storage\SQL\Util;
9use Projom\Storage\SQL\Util\Aggregate;
10
11class Column implements ComponentInterface
12{
13    private readonly array $fields;
14    private readonly string $fieldString;
15
16    public function __construct(array $fields)
17    {
18        $this->fields = $fields;
19        $this->parse($fields);
20    }
21
22    public static function create(array $fields): Column
23    {
24        return new Column($fields);
25    }
26
27    public function __toString(): string
28    {
29        return $this->fieldString;
30    }
31
32    public function empty(): bool
33    {
34        return empty($this->fields);
35    }
36
37    public function fields(): array
38    {
39        return $this->fields;
40    }
41
42    private function parse(array $fields): void
43    {
44        $parts = [];
45        foreach ($fields as $field) {
46
47            // If a field does not match it will be ignored.
48            if (!$matches = $this->matchField($field))
49                continue;
50
51            $parts[] = $this->createField($matches);
52        }
53
54        $this->fieldString = Util::join($parts, ', ');
55    }
56    private function matchField(string $field): array
57    {
58        $cases = Util::join(Aggregate::values(), '|');
59        $pattern = "/^({$cases})?\(?([\w\.\*]+)\)?(\s+as\s+[\w\.]+)?$/i";
60        $matches = Util::match($pattern, $field);
61        return $matches;
62    }
63
64    private function createField(array $matches): null|string
65    {
66        $function = Util::cleanString($matches[1]);
67        $field = Util::cleanString($matches[2]);
68        $alias = Util::cleanString($matches[3] ?? '');
69
70        if ($alias)
71            $alias = $this->transformAlias($alias);
72
73        if ($function)
74            return $this->buildAggregate($function, $field, $alias);
75
76        return $this->buildField($field, $alias);
77    }
78
79    private function transformAlias(string $alias): string
80    {
81        $alias = substr($alias, 2);
82        return $alias;
83    }
84
85    private function buildAggregate(string $function, string $field, string $alias): null|string
86    {
87        $function = strtoupper($function);
88        if (!$function = Aggregate::tryFrom($function))
89            return null;
90
91        $field = Util::splitAndQuoteThenJoin($field, '.');
92        $aggregate = $function->buildSQL($field, $alias);
93
94        return $aggregate;
95    }
96
97    private function buildField(string $field, string $alias): string
98    {
99        $field = Util::splitAndQuoteThenJoin($field, '.');
100        if ($alias)
101            return "$field AS $alias";
102        return $field;
103    }
104}