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