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