packages/sql-faker/bench/Bench.php

1<?php
2
3declare(strict_types=1);
4
5namespace Bench;
6
7use Faker\Factory;
8use PhpBench\Attributes as Benchmark;
9use SqlFaker\Generation\Plan\GenerationPlan;
10use SqlFaker\Generation\SqlGenerator;
11use SqlFaker\MySql\Generation\GenerationContext as MySqlContext;
12use SqlFaker\MySql\Grammar\MySqlGrammar;
13use SqlFaker\PostgreSql\Generation\GenerationContext as PostgreSqlContext;
14use SqlFaker\PostgreSql\Grammar\PgGrammar;
15use SqlFaker\Sqlite\Generation\GenerationContext as SqliteContext;
16use SqlFaker\Sqlite\Grammar\SqliteGrammar;
17
18/**
19 * Measures SQL generation using each dialect's grammar and lexical definitions.
20 */
21final class Bench
22{
23    private SqlGenerator $generator;
24
25    /** @var GenerationPlan<true> */
26    private GenerationPlan $plan;
27
28    /**
29     * Prepares the generator and SELECT plan before measurement.
30     * @param array{dialect: 'mysql'|'postgres'|'sqlite', rule: string} $params
31     */
32    public function setUp(array $params): void
33    {
34        $faker = Factory::create();
35        $faker->seed(2001);
36        $context = match ($params['dialect']) {
37            'mysql' => new MySqlContext(MySqlGrammar::load('mysql-8.4.7')->identified(), $faker, 'mysql-8.4.7'),
38            'postgres' => new PostgreSqlContext(PgGrammar::load('pg-17.2')->identified(), $faker, 'pg-17.2'),
39            'sqlite' => new SqliteContext(SqliteGrammar::load('sqlite-3.47.2')->identified(), $faker, 'sqlite-3.47.2'),
40        };
41        $this->generator = new SqlGenerator($context->grammar, $faker, $context->lexicalGrammar, $context->rewriter, $context->startSymbol);
42        $this->plan = GenerationPlan::fromRule($params['rule'])->withMaxDepth(6)->withStepBudget()->requiringNonEmpty();
43    }
44
45    /**
46     * Lists the dialects and their SELECT start rules.
47     * @return array<string, array{dialect: 'mysql'|'postgres'|'sqlite', rule: string}>
48     */
49    public function provideDialects(): array
50    {
51        return [
52            'mysql' => ['dialect' => 'mysql', 'rule' => 'select_stmt'],
53            'postgres' => ['dialect' => 'postgres', 'rule' => 'SelectStmt'],
54            'sqlite' => ['dialect' => 'sqlite', 'rule' => 'select'],
55        ];
56    }
57
58    /**
59     * Generates a SELECT statement directly through the SQL engine.
60     */
61    #[Benchmark\BeforeMethods('setUp')]
62    #[Benchmark\ParamProviders('provideDialects')]
63    #[Benchmark\Revs(250)]
64    public function benchSqlGeneration(): void
65    {
66        $this->generator->generate($this->plan);
67    }
68}
69