|
4 | 4 |
|
5 | 5 | use Utopia\Query\Exception\ValidationException; |
6 | 6 | use Utopia\Query\Schema\ClickHouse\Engine; |
| 7 | +use Utopia\Query\Schema\ClickHouse\SkipIndex; |
| 8 | +use Utopia\Query\Schema\ClickHouse\SkipIndexAlgorithm; |
7 | 9 |
|
8 | 10 | class Table |
9 | 11 | { |
@@ -51,6 +53,12 @@ class Table |
51 | 53 |
|
52 | 54 | public private(set) ?string $ttl = null; |
53 | 55 |
|
| 56 | + /** @var list<SkipIndex> ClickHouse data-skipping indexes (other dialects ignore) */ |
| 57 | + public private(set) array $skipIndexes = []; |
| 58 | + |
| 59 | + /** @var array<string, string> Table-level engine SETTINGS (ClickHouse only) */ |
| 60 | + public private(set) array $settings = []; |
| 61 | + |
54 | 62 | /** |
55 | 63 | * Add a table-level CHECK constraint. |
56 | 64 | * |
@@ -543,4 +551,87 @@ public function ttl(string $expression): static |
543 | 551 |
|
544 | 552 | return $this; |
545 | 553 | } |
| 554 | + |
| 555 | + /** |
| 556 | + * Attach a ClickHouse data-skipping index. Other dialects ignore this. |
| 557 | + * |
| 558 | + * Skip indexes accelerate WHERE clauses by letting ClickHouse skip whole |
| 559 | + * granules during scanning. Choose the algorithm that matches the column |
| 560 | + * cardinality and predicate type: |
| 561 | + * |
| 562 | + * - `MinMax` — numeric ranges, low cardinality |
| 563 | + * - `Set(N)` — small fixed value sets (N is the set size cap) |
| 564 | + * - `BloomFilter(p)` — high cardinality string columns with `=` / `IN` |
| 565 | + * predicates (p is the false-positive probability, e.g. 0.01) |
| 566 | + * - `NgramBloomFilter(n, size, hashes, seed)` — `LIKE` / `match` on text |
| 567 | + * - `TokenBloomFilter(size, hashes, seed)` — token-style search |
| 568 | + * - `Inverted` — `LIKE`, `match`, `hasToken` (experimental) |
| 569 | + * |
| 570 | + * @param list<string> $columns |
| 571 | + * @param list<string|int|float> $algorithmArgs Algorithm-specific arguments |
| 572 | + * |
| 573 | + * @throws ValidationException if the index name or columns are invalid. |
| 574 | + */ |
| 575 | + public function dataSkippingIndex( |
| 576 | + array $columns, |
| 577 | + SkipIndexAlgorithm $algorithm, |
| 578 | + int $granularity = 1, |
| 579 | + array $algorithmArgs = [], |
| 580 | + string $name = '', |
| 581 | + ): static { |
| 582 | + if ($name === '') { |
| 583 | + $name = 'skip_' . \implode('_', $columns); |
| 584 | + } |
| 585 | + |
| 586 | + $this->skipIndexes[] = new SkipIndex($name, $columns, $algorithm, $algorithmArgs, $granularity); |
| 587 | + |
| 588 | + return $this; |
| 589 | + } |
| 590 | + |
| 591 | + /** |
| 592 | + * Set table-level engine SETTINGS (ClickHouse only). Other dialects ignore. |
| 593 | + * |
| 594 | + * Compiled as `SETTINGS k=v, ...` after the TTL clause. Booleans become |
| 595 | + * `1` / `0`, ints/floats are stringified, strings are passed through after |
| 596 | + * a conservative character allow-list check. |
| 597 | + * |
| 598 | + * Calling this method replaces previously-set settings. |
| 599 | + * |
| 600 | + * @param array<string, string|int|float|bool> $settings |
| 601 | + * |
| 602 | + * @throws ValidationException if any key is not a valid identifier or any |
| 603 | + * string value contains characters outside the |
| 604 | + * allow-list. |
| 605 | + */ |
| 606 | + public function settings(array $settings): static |
| 607 | + { |
| 608 | + $sanitized = []; |
| 609 | + |
| 610 | + foreach ($settings as $key => $value) { |
| 611 | + if (! \preg_match('/^[A-Za-z_][A-Za-z0-9_]*$/', $key)) { |
| 612 | + throw new ValidationException('Invalid setting name: ' . $key); |
| 613 | + } |
| 614 | + |
| 615 | + if (\is_bool($value)) { |
| 616 | + $sanitized[$key] = $value ? '1' : '0'; |
| 617 | + } elseif (\is_int($value) || \is_float($value)) { |
| 618 | + $sanitized[$key] = (string) $value; |
| 619 | + } elseif (\is_string($value)) { |
| 620 | + if (! \preg_match('/^[A-Za-z0-9_.\-+\/]*$/', $value)) { |
| 621 | + throw new ValidationException( |
| 622 | + 'Invalid setting value for ' . $key . ': must match [A-Za-z0-9_.\\-+/]*' |
| 623 | + ); |
| 624 | + } |
| 625 | + $sanitized[$key] = $value; |
| 626 | + } else { |
| 627 | + throw new ValidationException( |
| 628 | + 'Setting value for ' . $key . ' must be string, int, float, or bool.' |
| 629 | + ); |
| 630 | + } |
| 631 | + } |
| 632 | + |
| 633 | + $this->settings = $sanitized; |
| 634 | + |
| 635 | + return $this; |
| 636 | + } |
546 | 637 | } |
0 commit comments