packages/ztd-query-sqlite/tests/Unit/Rewrite/Upsert/UpsertExpressionBinderTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Rewrite\Upsert;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\UsesClass;
9use PHPUnit\Framework\TestCase;
10use ZtdQuery\Platform\Sqlite\Rewrite\Upsert\UpsertExpressionBinder;
11use ZtdQuery\Platform\Sqlite\Sql\SqliteLexerProfile;
12use ZtdQuery\Sql\SqlToken;
13use ZtdQuery\Sql\SqlTokenKind;
14use ZtdQuery\Sql\SqlTokenStream;
15
16#[CoversClass(UpsertExpressionBinder::class)]
17#[UsesClass(\ZtdQuery\Platform\Sqlite\Rewrite\SqlEdits::class)]
18#[UsesClass(\ZtdQuery\Platform\Sqlite\Rewrite\Upsert\UpsertConflictPredicate::class)]
19#[UsesClass(\ZtdQuery\Platform\Sqlite\Sql\SqliteIdentifierQuoter::class)]
20#[UsesClass(SqliteLexerProfile::class)]
21final class UpsertExpressionBinderTest extends TestCase
22{
23 public function testBindExpressionBindsIncomingExistingAndUnqualifiedColumns(): void
24 {
25 $binder = new UpsertExpressionBinder(['EXCLUDED'], new \ZtdQuery\Platform\Sqlite\Sql\SqliteIdentifierQuoter());
26 self::assertSame('"__ztd_incoming"."count" + "__ztd_existing"."count" + "__ztd_existing"."count"', $binder->bindExpression('EXCLUDED.count + users.count + count', 'users', ['count']));
27 self::assertSame('upper("__ztd_existing"."name") || \'name\'', $binder->bindExpression("upper(name) || 'name'", 'users', ['name']));
28 self::assertSame('other.count + (SELECT count FROM log)', $binder->bindExpression('other.count + (SELECT count FROM log)', 'users', ['count']));
29 self::assertSame('"candidate"."count"', $binder->bindExpression('count', 'users', ['count'], 'candidate'));
30 }
31
32 public function testSubqueryTokenIndexesMarksOnlyNestedQueryTokens(): void
33 {
34 $binder = new UpsertExpressionBinder(['EXCLUDED'], new \ZtdQuery\Platform\Sqlite\Sql\SqliteIdentifierQuoter());
35 self::assertSame([1 => true, 2 => true, 3 => true, 4 => true], $binder->subqueryTokenIndexes(SqlTokenStream::tokenize('(SELECT count FROM log) + count', SqliteLexerProfile::create())->significantTokens()));
36 self::assertSame([], $binder->subqueryTokenIndexes(SqlTokenStream::tokenize('SELECT count FROM log', SqliteLexerProfile::create())->significantTokens()));
37 }
38
39 public function testIsIdentifierDistinguishesColumnNames(): void
40 {
41 $binder = new UpsertExpressionBinder(['EXCLUDED'], new \ZtdQuery\Platform\Sqlite\Sql\SqliteIdentifierQuoter());
42 self::assertTrue($binder->isIdentifier(new SqlToken(SqlTokenKind::Word, 'name', 0, 0, 0)));
43 self::assertFalse($binder->isIdentifier(new SqlToken(SqlTokenKind::String, "'name'", 0, 0, 0)));
44 }
45
46 public function testIdentifierUnquotesEscapedNames(): void
47 {
48 $binder = new UpsertExpressionBinder(['EXCLUDED'], new \ZtdQuery\Platform\Sqlite\Sql\SqliteIdentifierQuoter());
49 self::assertSame('a"b', $binder->identifier(new SqlToken(SqlTokenKind::QuotedIdentifier, '"a""b"', 0, 0, 0)));
50 self::assertSame('name', $binder->identifier(new SqlToken(SqlTokenKind::Word, 'name', 0, 0, 0)));
51 }
52
53}
54