Skip to content

Commit 1af51f9

Browse files
authored
Support boolean type (#319)
1 parent 1a6d5a2 commit 1af51f9

13 files changed

+140
-13
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
- Enh #313: Refactor according changes in `db` package (@Tigrov)
4242
- New #311: Add `caseSensitive` option to like condition (@vjik)
4343
- Enh #315: Remove `getCacheKey()` and `getCacheTag()` methods from `Schema` class (@Tigrov)
44+
- Enh #319: Support `boolean` type (@Tigrov)
4445
- Enh #318, #320: Use `DbArrayHelper::arrange()` instead of `DbArrayHelper::index()` method (@Tigrov)
4546

4647
## 1.3.0 March 21, 2024

src/Column/BooleanColumn.php

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Yiisoft\Db\Oracle\Column;
6+
7+
use Yiisoft\Db\Constant\ColumnType;
8+
use Yiisoft\Db\Constant\PhpType;
9+
use Yiisoft\Db\Expression\ExpressionInterface;
10+
use Yiisoft\Db\Schema\Column\AbstractColumn;
11+
12+
final class BooleanColumn extends AbstractColumn
13+
{
14+
protected const DEFAULT_TYPE = ColumnType::BOOLEAN;
15+
16+
public function dbTypecast(mixed $value): string|ExpressionInterface|null
17+
{
18+
return match ($value) {
19+
true => '1',
20+
false => '0',
21+
null, '' => null,
22+
default => $value instanceof ExpressionInterface ? $value : ($value ? '1' : '0'),
23+
};
24+
}
25+
26+
/** @psalm-mutation-free */
27+
public function getPhpType(): string
28+
{
29+
return PhpType::BOOL;
30+
}
31+
32+
public function phpTypecast(mixed $value): bool|null
33+
{
34+
if ($value === null) {
35+
return null;
36+
}
37+
38+
return $value && $value !== "\0";
39+
}
40+
}

src/Column/ColumnBuilder.php

+5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ public static function binary(int|null $size = null): BinaryColumn
1313
return new BinaryColumn(ColumnType::BINARY, size: $size);
1414
}
1515

16+
public static function boolean(): BooleanColumn
17+
{
18+
return new BooleanColumn(ColumnType::BOOLEAN);
19+
}
20+
1621
public static function json(): JsonColumn
1722
{
1823
return new JsonColumn(ColumnType::JSON);

src/Column/ColumnDefinitionBuilder.php

+7-3
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,17 @@ protected function buildCheck(ColumnInterface $column): string
5656
if (empty($check)) {
5757
$name = $column->getName();
5858

59-
if (empty($name) || version_compare($this->queryBuilder->getServerInfo()->getVersion(), '21', '>=')) {
59+
if (empty($name)) {
6060
return '';
6161
}
6262

6363
return match ($column->getType()) {
6464
ColumnType::ARRAY, ColumnType::STRUCTURED, ColumnType::JSON =>
65-
' CHECK (' . $this->queryBuilder->getQuoter()->quoteSimpleColumnName($name) . ' IS JSON)',
65+
version_compare($this->queryBuilder->getServerInfo()->getVersion(), '21', '<')
66+
? ' CHECK (' . $this->queryBuilder->getQuoter()->quoteSimpleColumnName($name) . ' IS JSON)'
67+
: '',
68+
ColumnType::BOOLEAN =>
69+
' CHECK (' . $this->queryBuilder->getQuoter()->quoteSimpleColumnName($name) . ' IN (0,1))',
6670
default => '',
6771
};
6872
}
@@ -94,7 +98,7 @@ protected function getDbType(ColumnInterface $column): string
9498
return match ($dbType) {
9599
default => $dbType,
96100
null => match ($column->getType()) {
97-
ColumnType::BOOLEAN => 'number(1)',
101+
ColumnType::BOOLEAN => 'char(1)',
98102
ColumnType::BIT => match (true) {
99103
$size === null => 'number(38)',
100104
$size <= 126 => 'number(' . ceil(log10(2 ** $size)) . ')',

src/Column/ColumnFactory.php

+13-2
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,18 @@ protected function getType(string $dbType, array $info = []): string
6565
};
6666
}
6767

68-
if (isset($info['check'], $info['name']) && strcasecmp($info['check'], '"' . $info['name'] . '" is json') === 0) {
69-
return ColumnType::JSON;
68+
if (isset($info['check'], $info['name'])) {
69+
if (strcasecmp($info['check'], '"' . $info['name'] . '" is json') === 0) {
70+
return ColumnType::JSON;
71+
}
72+
73+
if (isset($info['size'])
74+
&& $dbType === 'char'
75+
&& $info['size'] === 1
76+
&& strcasecmp($info['check'], '"' . $info['name'] . '" in (0,1)') === 0
77+
) {
78+
return ColumnType::BOOLEAN;
79+
}
7080
}
7181

7282
if ($dbType === 'interval day to second' && isset($info['scale']) && $info['scale'] === 0) {
@@ -80,6 +90,7 @@ protected function getColumnClass(string $type, array $info = []): string
8090
{
8191
return match ($type) {
8292
ColumnType::BINARY => BinaryColumn::class,
93+
ColumnType::BOOLEAN => BooleanColumn::class,
8394
ColumnType::JSON => JsonColumn::class,
8495
default => parent::getColumnClass($type, $info),
8596
};

src/QueryBuilder.php

+4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
*/
1616
final class QueryBuilder extends AbstractQueryBuilder
1717
{
18+
protected const FALSE_VALUE = "'0'";
19+
20+
protected const TRUE_VALUE = "'1'";
21+
1822
public function __construct(ConnectionInterface $db)
1923
{
2024
$quoter = $db->getQuoter();

tests/ColumnTest.php

+9-1
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
namespace Yiisoft\Db\Oracle\Tests;
66

77
use PDO;
8+
use PHPUnit\Framework\Attributes\DataProviderExternal;
89
use Yiisoft\Db\Command\Param;
910
use Yiisoft\Db\Expression\Expression;
1011
use Yiisoft\Db\Oracle\Column\BinaryColumn;
1112
use Yiisoft\Db\Oracle\Column\JsonColumn;
13+
use Yiisoft\Db\Oracle\Tests\Provider\ColumnProvider;
1214
use Yiisoft\Db\Oracle\Tests\Support\TestTrait;
1315
use Yiisoft\Db\Query\Query;
1416
use Yiisoft\Db\Schema\Column\ColumnInterface;
@@ -106,12 +108,18 @@ public function testPredefinedType(string $className, string $type, string $phpT
106108
parent::testPredefinedType($className, $type, $phpType);
107109
}
108110

109-
/** @dataProvider \Yiisoft\Db\Oracle\Tests\Provider\ColumnProvider::dbTypecastColumns */
111+
#[DataProviderExternal(ColumnProvider::class, 'dbTypecastColumns')]
110112
public function testDbTypecastColumns(ColumnInterface $column, array $values): void
111113
{
112114
parent::testDbTypecastColumns($column, $values);
113115
}
114116

117+
#[DataProviderExternal(ColumnProvider::class, 'phpTypecastColumns')]
118+
public function testPhpTypecastColumns(ColumnInterface $column, array $values): void
119+
{
120+
parent::testPhpTypecastColumns($column, $values);
121+
}
122+
115123
public function testBinaryColumn(): void
116124
{
117125
$binaryCol = new BinaryColumn();

tests/Provider/ColumnBuilderProvider.php

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Yiisoft\Db\Oracle\Tests\Provider;
66

77
use Yiisoft\Db\Oracle\Column\BinaryColumn;
8+
use Yiisoft\Db\Oracle\Column\BooleanColumn;
89
use Yiisoft\Db\Oracle\Column\JsonColumn;
910

1011
class ColumnBuilderProvider extends \Yiisoft\Db\Tests\Provider\ColumnBuilderProvider
@@ -15,6 +16,7 @@ public static function buildingMethods(): array
1516

1617
$values['binary()'][2] = BinaryColumn::class;
1718
$values['binary(8)'][2] = BinaryColumn::class;
19+
$values['boolean()'][2] = BooleanColumn::class;
1820
$values['json()'][2] = JsonColumn::class;
1921

2022
return $values;

tests/Provider/ColumnFactoryProvider.php

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Yiisoft\Db\Constant\ColumnType;
88
use Yiisoft\Db\Expression\Expression;
99
use Yiisoft\Db\Oracle\Column\BinaryColumn;
10+
use Yiisoft\Db\Oracle\Column\BooleanColumn;
1011
use Yiisoft\Db\Oracle\Column\JsonColumn;
1112
use Yiisoft\Db\Schema\Column\ArrayColumn;
1213
use Yiisoft\Db\Schema\Column\BigIntColumn;
@@ -85,6 +86,8 @@ public static function types(): array
8586
{
8687
$types = parent::types();
8788

89+
$types['binary'][2] = BinaryColumn::class;
90+
$types['boolean'][2] = BooleanColumn::class;
8891
$types['json'][2] = JsonColumn::class;
8992

9093
return $types;

tests/Provider/ColumnProvider.php

+32
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,19 @@
44

55
namespace Yiisoft\Db\Oracle\Tests\Provider;
66

7+
use Yiisoft\Db\Expression\Expression;
78
use Yiisoft\Db\Oracle\Column\BinaryColumn;
9+
use Yiisoft\Db\Oracle\Column\BooleanColumn;
10+
use Yiisoft\Db\Oracle\Column\JsonColumn;
811

912
class ColumnProvider extends \Yiisoft\Db\Tests\Provider\ColumnProvider
1013
{
1114
public static function predefinedTypes(): array
1215
{
1316
$values = parent::predefinedTypes();
1417
$values['binary'][0] = BinaryColumn::class;
18+
$values['boolean'][0] = BooleanColumn::class;
19+
$values['json'][0] = JsonColumn::class;
1520

1621
return $values;
1722
}
@@ -20,6 +25,33 @@ public static function dbTypecastColumns(): array
2025
{
2126
$values = parent::dbTypecastColumns();
2227
$values['binary'][0] = new BinaryColumn();
28+
$values['boolean'] = [
29+
new BooleanColumn(),
30+
[
31+
[null, null],
32+
[null, ''],
33+
['1', true],
34+
['1', 1],
35+
['1', 1.0],
36+
['1', '1'],
37+
['0', false],
38+
['0', 0],
39+
['0', 0.0],
40+
['0', '0'],
41+
[$expression = new Expression('expression'), $expression],
42+
],
43+
];
44+
$values['json'][0] = new JsonColumn();
45+
46+
return $values;
47+
}
48+
49+
public static function phpTypecastColumns(): array
50+
{
51+
$values = parent::phpTypecastColumns();
52+
$values['binary'][0] = new BinaryColumn();
53+
$values['boolean'][0] = new BooleanColumn();
54+
$values['json'][0] = new JsonColumn();
2355

2456
return $values;
2557
}

tests/Provider/CommandProvider.php

+14
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,20 @@ public static function insertVarbinary(): array
9999
];
100100
}
101101

102+
public static function rawSql(): array
103+
{
104+
$rawSql = parent::rawSql();
105+
106+
foreach ($rawSql as &$values) {
107+
$values[2] = strtr($values[2], [
108+
'FALSE' => "'0'",
109+
'TRUE' => "'1'",
110+
]);
111+
}
112+
113+
return $rawSql;
114+
}
115+
102116
public static function createIndex(): array
103117
{
104118
return [

tests/Provider/QueryBuilderProvider.php

+6-2
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,8 @@ public static function buildColumnDefinition(): array
271271
$values['bigPrimaryKey(false)'][0] = 'number(20) PRIMARY KEY';
272272
$values['uuidPrimaryKey()'][0] = 'raw(16) DEFAULT sys_guid() PRIMARY KEY';
273273
$values['uuidPrimaryKey(false)'][0] = 'raw(16) PRIMARY KEY';
274-
$values['boolean()'][0] = 'number(1)';
275-
$values['boolean(100)'][0] = 'number(1)';
274+
$values['boolean()'] = ['char(1) CHECK ("boolean_col" IN (0,1))', $values['boolean()'][1]->withName('boolean_col')];
275+
$values['boolean(100)'] = ['char(1) CHECK ("boolean_100" IN (0,1))', $values['boolean(100)'][1]->withName('boolean_100')];
276276
$values['bit()'][0] = 'number(38)';
277277
$values['bit(1)'][0] = 'number(1)';
278278
$values['bit(8)'][0] = 'number(3)';
@@ -384,6 +384,8 @@ public static function prepareParam(): array
384384
{
385385
$values = parent::prepareParam();
386386

387+
$values['true'][0] = "'1'";
388+
$values['false'][0] = "'0'";
387389
$values['binary'][0] = "HEXTORAW('737472696e67')";
388390

389391
return $values;
@@ -393,6 +395,8 @@ public static function prepareValue(): array
393395
{
394396
$values = parent::prepareValue();
395397

398+
$values['true'][0] = "'1'";
399+
$values['false'][0] = "'0'";
396400
$values['binary'][0] = "HEXTORAW('737472696e67')";
397401
$values['paramBinary'][0] = "HEXTORAW('737472696e67')";
398402

tests/Provider/SchemaProvider.php

+4-5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Yiisoft\Db\Constraint\CheckConstraint;
99
use Yiisoft\Db\Expression\Expression;
1010
use Yiisoft\Db\Oracle\Column\BinaryColumn;
11+
use Yiisoft\Db\Oracle\Column\BooleanColumn;
1112
use Yiisoft\Db\Oracle\Column\JsonColumn;
1213
use Yiisoft\Db\Schema\Column\DoubleColumn;
1314
use Yiisoft\Db\Schema\Column\IntegerColumn;
@@ -102,19 +103,17 @@ public static function columns(): array
102103
scale: 1,
103104
defaultValue: new Expression("INTERVAL '2 04:56:12' DAY(1) TO SECOND(0)"),
104105
),
105-
'bool_col' => new StringColumn(
106-
ColumnType::CHAR,
106+
'bool_col' => new BooleanColumn(
107107
dbType: 'char',
108108
check: '"bool_col" in (0,1)',
109109
notNull: true,
110110
size: 1,
111111
),
112-
'bool_col2' => new StringColumn(
113-
ColumnType::CHAR,
112+
'bool_col2' => new BooleanColumn(
114113
dbType: 'char',
115114
check: '"bool_col2" in (0,1)',
116115
size: 1,
117-
defaultValue: '1',
116+
defaultValue: true,
118117
),
119118
'ts_default' => new StringColumn(
120119
ColumnType::TIMESTAMP,

0 commit comments

Comments
 (0)