Skip to content

Commit 0688263

Browse files
authored
Realize Schema::loadResultColumn() method (#348)
1 parent e170b66 commit 0688263

5 files changed

Lines changed: 257 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
- New #344: Add `caseSensitive` option to like condition (@vjik)
3636
- Enh #347: Remove `getCacheKey()` and `getCacheTag()` methods from `Schema` class (@Tigrov)
3737
- Enh #350, #351: Use `DbArrayHelper::arrange()` instead of `DbArrayHelper::index()` method (@Tigrov)
38+
- New #348: Realize `Schema::loadResultColumn()` method (@Tigrov)
3839

3940
## 1.2.0 March 21, 2024
4041

src/Schema.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,40 @@ public function getSchemaDefaultValues(string $schema = '', bool $refresh = fals
416416
throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.');
417417
}
418418

419+
/**
420+
* @psalm-param array{
421+
* native_type: string,
422+
* pdo_type: int,
423+
* "sqlite:decl_type"?: string,
424+
* table?: string,
425+
* flags: string[],
426+
* name: string,
427+
* len: int,
428+
* precision: int,
429+
* } $metadata
430+
*
431+
* @psalm-suppress MoreSpecificImplementedParamType
432+
*/
433+
protected function loadResultColumn(array $metadata): ColumnInterface|null
434+
{
435+
if (empty($metadata['sqlite:decl_type']) && (empty($metadata['native_type']) || $metadata['native_type'] === 'null')) {
436+
return null;
437+
}
438+
439+
$dbType = $metadata['sqlite:decl_type'] ?? $metadata['native_type'];
440+
441+
$columnInfo = ['fromResult' => true];
442+
443+
if (!empty($metadata['table'])) {
444+
$columnInfo['table'] = $metadata['table'];
445+
$columnInfo['name'] = $metadata['name'];
446+
} elseif (!empty($metadata['name'])) {
447+
$columnInfo['name'] = $metadata['name'];
448+
}
449+
450+
return $this->db->getColumnFactory()->fromDefinition($dbType, $columnInfo);
451+
}
452+
419453
/**
420454
* Loads the column information into a {@see ColumnInterface} object.
421455
*

tests/ColumnTest.php

Lines changed: 90 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Yiisoft\Db\Schema\Column\IntegerColumn;
1313
use Yiisoft\Db\Schema\Column\JsonColumn;
1414
use Yiisoft\Db\Schema\Column\StringColumn;
15+
use Yiisoft\Db\Sqlite\Connection;
1516
use Yiisoft\Db\Sqlite\Tests\Support\TestTrait;
1617
use Yiisoft\Db\Query\Query;
1718
use Yiisoft\Db\Tests\AbstractColumnTest;
@@ -25,13 +26,9 @@ final class ColumnTest extends AbstractColumnTest
2526
{
2627
use TestTrait;
2728

28-
public function testPhpTypeCast(): void
29+
private function insertTypeValues(Connection $db): void
2930
{
30-
$db = $this->getConnection(true);
31-
3231
$command = $db->createCommand();
33-
$schema = $db->getSchema();
34-
$tableSchema = $schema->getTableSchema('type');
3532

3633
$command->insert(
3734
'type',
@@ -49,9 +46,95 @@ public function testPhpTypeCast(): void
4946
]
5047
);
5148
$command->execute();
52-
$query = (new Query($db))->from('type')->one();
49+
}
50+
51+
private function assertResultValues(array $result): void
52+
{
53+
$this->assertSame(1, $result['int_col']);
54+
$this->assertSame(str_repeat('x', 100), $result['char_col']);
55+
$this->assertNull($result['char_col3']);
56+
$this->assertSame(1.234, $result['float_col']);
57+
$this->assertSame("\x10\x11\x12", $result['blob_col']);
58+
$this->assertSame('2023-07-11 14:50:23', $result['timestamp_col']);
59+
$this->assertFalse($result['bool_col']);
60+
$this->assertSame(0b0110_0110, $result['bit_col']);
61+
$this->assertSame([['a' => 1, 'b' => null, 'c' => [1, 3, 5]]], $result['json_col']);
62+
$this->assertSame('[1,2,3,"string",null]', $result['json_text_col']);
63+
}
64+
65+
public function testQueryWithTypecasting(): void
66+
{
67+
$db = $this->getConnection(true);
68+
69+
$this->insertTypeValues($db);
70+
71+
$query = (new Query($db))->from('type')->withTypecasting();
72+
73+
$result = $query->one();
74+
75+
$this->assertResultValues($result);
76+
77+
$result = $query->all();
78+
79+
$this->assertResultValues($result[0]);
80+
81+
$db->close();
82+
}
83+
84+
public function testCommandWithPhpTypecasting(): void
85+
{
86+
$db = $this->getConnection(true);
87+
88+
$this->insertTypeValues($db);
5389

54-
$this->assertNotNull($tableSchema);
90+
$command = $db->createCommand('SELECT * FROM type')->withPhpTypecasting();
91+
92+
$result = $command->queryOne();
93+
94+
$this->assertResultValues($result);
95+
96+
$result = $command->queryAll();
97+
98+
$this->assertResultValues($result[0]);
99+
100+
$db->close();
101+
}
102+
103+
public function testSelectWithPhpTypecasting(): void
104+
{
105+
$db = $this->getConnection();
106+
107+
$result = $db->createCommand("SELECT null, 1, 2.5, true, false, 'string'")
108+
->withPhpTypecasting()
109+
->queryOne();
110+
111+
$this->assertSame([
112+
'null' => null,
113+
1 => 1,
114+
'2.5' => 2.5,
115+
'true' => 1,
116+
'false' => 0,
117+
'\'string\'' => 'string',
118+
], $result);
119+
120+
$result = $db->createCommand('SELECT 2.5')
121+
->withPhpTypecasting()
122+
->queryScalar();
123+
124+
$this->assertSame(2.5, $result);
125+
126+
$db->close();
127+
}
128+
129+
public function testPhpTypeCast(): void
130+
{
131+
$db = $this->getConnection(true);
132+
$schema = $db->getSchema();
133+
$tableSchema = $schema->getTableSchema('type');
134+
135+
$this->insertTypeValues($db);
136+
137+
$query = (new Query($db))->from('type')->one();
55138

56139
$intColPhpType = $tableSchema->getColumn('int_col')?->phpTypecast($query['int_col']);
57140
$charColPhpType = $tableSchema->getColumn('char_col')?->phpTypecast($query['char_col']);

tests/Provider/SchemaProvider.php

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Yiisoft\Db\Constant\ColumnType;
88
use Yiisoft\Db\Expression\Expression;
9+
use Yiisoft\Db\Schema\Column\ArrayColumn;
910
use Yiisoft\Db\Schema\Column\BinaryColumn;
1011
use Yiisoft\Db\Schema\Column\BitColumn;
1112
use Yiisoft\Db\Schema\Column\BooleanColumn;
@@ -219,4 +220,126 @@ public static function constraints(): array
219220

220221
return $constraints;
221222
}
223+
224+
public static function resultColumns(): array
225+
{
226+
return [
227+
[null, []],
228+
[null, ['native_type' => 'null']],
229+
[new IntegerColumn(dbType: 'integer', name: 'int_col'), [
230+
'native_type' => 'null',
231+
'pdo_type' => 0,
232+
'sqlite:decl_type' => 'INTEGER',
233+
'table' => 'type',
234+
'flags' => [],
235+
'name' => 'int_col',
236+
'len' => -1,
237+
'precision' => 0,
238+
]],
239+
[new IntegerColumn(ColumnType::TINYINT, dbType: 'tinyint', name: 'tinyint_col', size: 3), [
240+
'native_type' => 'null',
241+
'pdo_type' => 0,
242+
'sqlite:decl_type' => 'TINYINT(3)',
243+
'table' => 'type',
244+
'flags' => [],
245+
'name' => 'tinyint_col',
246+
'len' => -1,
247+
'precision' => 0,
248+
]],
249+
[new StringColumn(dbType: 'varchar', name: 'char_col2', size: 100), [
250+
'native_type' => 'null',
251+
'pdo_type' => 0,
252+
'sqlite:decl_type' => 'varchar(100)',
253+
'table' => 'type',
254+
'flags' => [],
255+
'name' => 'char_col2',
256+
'len' => -1,
257+
'precision' => 0,
258+
]],
259+
[new DoubleColumn(dbType: 'double', name: 'float_col', size: 4, scale: 3), [
260+
'native_type' => 'null',
261+
'pdo_type' => 0,
262+
'sqlite:decl_type' => 'double(4,3)',
263+
'table' => 'type',
264+
'flags' => [],
265+
'name' => 'float_col',
266+
'len' => -1,
267+
'precision' => 0,
268+
]],
269+
[new StringColumn(ColumnType::TIMESTAMP, dbType: 'timestamp', name: 'timestamp_col'), [
270+
'native_type' => 'null',
271+
'pdo_type' => 0,
272+
'sqlite:decl_type' => 'timestamp',
273+
'table' => 'type',
274+
'flags' => [],
275+
'name' => 'timestamp_col',
276+
'len' => -1,
277+
'precision' => 0,
278+
]],
279+
[new BooleanColumn(dbType: 'tinyint', name: 'bool_col', size: 1), [
280+
'native_type' => 'null',
281+
'pdo_type' => 0,
282+
'sqlite:decl_type' => 'tinyint(1)',
283+
'table' => 'type',
284+
'flags' => [],
285+
'name' => 'bool_col',
286+
'len' => -1,
287+
'precision' => 0,
288+
]],
289+
[new BitColumn(dbType: 'bit', name: 'bit_col', size: 8), [
290+
'native_type' => 'null',
291+
'pdo_type' => 0,
292+
'sqlite:decl_type' => 'BIT(8)',
293+
'table' => 'type',
294+
'flags' => [],
295+
'name' => 'bit_col',
296+
'len' => -1,
297+
'precision' => 0,
298+
]],
299+
[new JsonColumn(dbType: 'json', name: 'json_col'), [
300+
'native_type' => 'null',
301+
'pdo_type' => 0,
302+
'sqlite:decl_type' => 'json',
303+
'table' => 'type',
304+
'flags' => [],
305+
'name' => 'json_col',
306+
'len' => -1,
307+
'precision' => 0,
308+
]],
309+
[new ArrayColumn(dbType: 'int', name: 'int_arr', dimension: 1, column: new IntegerColumn(dbType: 'int', name: 'int_arr')), [
310+
'native_type' => 'null',
311+
'pdo_type' => 0,
312+
'sqlite:decl_type' => 'int[]',
313+
'table' => 'type',
314+
'flags' => [],
315+
'name' => 'int_arr',
316+
'len' => -1,
317+
'precision' => 0,
318+
]],
319+
[new IntegerColumn(dbType: 'integer', name: '1'), [
320+
'native_type' => 'integer',
321+
'pdo_type' => 1,
322+
'flags' => [],
323+
'name' => '1',
324+
'len' => -1,
325+
'precision' => 0,
326+
]],
327+
[new DoubleColumn(dbType: 'double', name: '2.5'), [
328+
'native_type' => 'double',
329+
'pdo_type' => 2,
330+
'flags' => [],
331+
'name' => '2.5',
332+
'len' => -1,
333+
'precision' => 0,
334+
]],
335+
[new StringColumn(name: 'string'), [
336+
'native_type' => 'string',
337+
'pdo_type' => 2,
338+
'flags' => [],
339+
'name' => 'string',
340+
'len' => -1,
341+
'precision' => 0,
342+
]],
343+
];
344+
}
222345
}

tests/SchemaTest.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@
55
namespace Yiisoft\Db\Sqlite\Tests;
66

77
use JsonException;
8+
use PHPUnit\Framework\Attributes\DataProviderExternal;
89
use Throwable;
910
use Yiisoft\Db\Connection\ConnectionInterface;
1011
use Yiisoft\Db\Constraint\CheckConstraint;
1112
use Yiisoft\Db\Exception\Exception;
1213
use Yiisoft\Db\Exception\InvalidConfigException;
1314
use Yiisoft\Db\Exception\NotSupportedException;
15+
use Yiisoft\Db\Schema\Column\ColumnInterface;
1416
use Yiisoft\Db\Sqlite\Schema;
17+
use Yiisoft\Db\Sqlite\Tests\Provider\SchemaProvider;
1518
use Yiisoft\Db\Sqlite\Tests\Support\TestTrait;
1619
use Yiisoft\Db\Tests\Common\CommonSchemaTest;
1720
use Yiisoft\Db\Tests\Support\DbHelper;
@@ -359,4 +362,10 @@ public function testNotConnectionPDO(): void
359362

360363
$schema->refresh();
361364
}
365+
366+
#[DataProviderExternal(SchemaProvider::class, 'resultColumns')]
367+
public function testGetResultColumn(ColumnInterface|null $expected, array $info): void
368+
{
369+
parent::testGetResultColumn($expected, $info);
370+
}
362371
}

0 commit comments

Comments
 (0)