diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e26152e..102b785 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - php-version: ['8.2', '8.3', '8.4'] + php-version: ['8.4'] dependency-versions: ['lowest', 'highest'] name: 'BlackBox' services: @@ -50,7 +50,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - php-version: ['8.2', '8.3', '8.4'] + php-version: ['8.4'] dependency-versions: ['lowest', 'highest'] name: 'Coverage' services: @@ -92,41 +92,6 @@ jobs: with: token: ${{ secrets.CODECOV_TOKEN }} psalm: - runs-on: ubuntu-latest - strategy: - matrix: - php-version: ['8.2', '8.3'] - dependencies: ['lowest', 'highest'] - name: 'Psalm' - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php-version }} - extensions: mbstring, intl - - name: Composer - uses: "ramsey/composer-install@v2" - with: - dependency-versions: ${{ matrix.dependencies }} - - name: Psalm - run: vendor/bin/psalm --shepherd + uses: innmind/github-workflows/.github/workflows/psalm-matrix.yml@next cs: - runs-on: ubuntu-latest - strategy: - matrix: - php-version: ['8.2'] - name: 'CS' - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php-version }} - extensions: mbstring, intl - - name: Composer - uses: "ramsey/composer-install@v2" - - name: CS - run: vendor/bin/php-cs-fixer fix --diff --dry-run + uses: innmind/github-workflows/.github/workflows/cs.yml@next diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 74cd16c..39064b6 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -2,27 +2,9 @@ name: Documentation on: push: branches: [master] - permissions: contents: write jobs: deploy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Configure Git Credentials - run: | - git config user.name github-actions[bot] - git config user.email 41898282+github-actions[bot]@users.noreply.github.com - - uses: actions/setup-python@v5 - with: - python-version: 3.x - - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV - - uses: actions/cache@v4 - with: - key: mkdocs-material-${{ env.cache_id }} - path: .cache - restore-keys: | - mkdocs-material- - - run: pip install mkdocs-material - - run: mkdocs gh-deploy --force + uses: innmind/github-workflows/.github/workflows/documentation.yml@main + secrets: inherit diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..b25ad8a --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,11 @@ +name: Create release + +on: + push: + tags: + - '*' + +jobs: + release: + uses: innmind/github-workflows/.github/workflows/release.yml@main + secrets: inherit diff --git a/CHANGELOG.md b/CHANGELOG.md index a3c05db..0544104 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,29 @@ # Changelog +## [Unreleased] + +### Added + +- `Formal\AccessLayer\Query\Builder` +- `Formal\AccessLayer\Query\SQL` named constructors allow to pass all the parameters at once via the second argument + +### Changed + +- Requires PHP `8.4` +- `Formal\AccessLayer\Connection` is now a final class, all previous implementations are now flagged as internal +- `Formal\AccessLayer\Query` is now a final class +- Requires `innmind/black-box:~6.5` + +### Deprecated + +- `Formal\AccessLayer\Query\Select::onDemand()`, use `::lazily()` instead +- `Formal\AccessLayer\Query\SQL`, use `Formal\AccessLayer\Query` instead + +### Removed + +- `Formal\AccessLayer\Connection\PDO::persistent()` +- `Formal\AccessLayer\Query\Where::sql()` and `::parameters()`, use `::normalize()` instead + ## 4.2.0 - 2025-04-09 ### Added diff --git a/composer.json b/composer.json index f79ac9a..9542587 100644 --- a/composer.json +++ b/composer.json @@ -15,9 +15,9 @@ "issues": "http://github.com/formal-php/access-layer/issues" }, "require": { - "php": "~8.2", - "innmind/immutable": "~4.0|~5.0", - "innmind/url": "~4.0", + "php": "~8.4", + "innmind/immutable": "dev-next", + "innmind/url": "dev-next", "innmind/specification": "~4.1", "psr/log": "~3.0" }, @@ -35,16 +35,16 @@ }, "require-dev": { "innmind/static-analysis": "^1.2.1", - "innmind/black-box": "^5.8|^6.0.2", + "innmind/black-box": "~6.5", "innmind/coding-standard": "~2.0" }, "conflict": { - "innmind/black-box": "<5.0|~7.0" + "innmind/black-box": "<6.0|~7.0" }, "suggest": { "innmind/black-box": "For property based testing" }, "provide": { - "innmind/black-box-sets": "5.0" + "innmind/black-box-sets": "6.0" } } diff --git a/fixtures/Table/Column.php b/fixtures/Table/Column.php index ba81fbb..110ab3d 100644 --- a/fixtures/Table/Column.php +++ b/fixtures/Table/Column.php @@ -13,13 +13,11 @@ final class Column */ public static function any(?Set $type = null, ?int $max = null): Set { - return Set\Randomize::of( // randomize to prevent same name used twice - Set\Composite::immutable( - Model::of(...), - Column\Name::any($max), - $type ?? Column\Type::any(), - ), - ); + return Set::compose( + Model::of(...), + Column\Name::any($max), + $type ?? Column\Type::any(), + )->randomize(); } /** @@ -27,7 +25,7 @@ public static function any(?Set $type = null, ?int $max = null): Set */ public static function list(): Set { - return Set\Sequence::of(self::any()) + return Set::sequence(self::any()) ->between(1, 20) ->map(static function($columns) { $filtered = []; diff --git a/fixtures/Table/Column/Name.php b/fixtures/Table/Column/Name.php index 9aca454..f46223c 100644 --- a/fixtures/Table/Column/Name.php +++ b/fixtures/Table/Column/Name.php @@ -15,10 +15,11 @@ public static function any(?int $max = null): Set { $max ??= 64; - return Set\Strings::madeOf( - Set\Chars::alphanumerical(), - Set\Elements::of('é', 'è', 'ê', 'ë', '_'), - ) + return Set::strings() + ->madeOf( + Set::strings()->chars()->alphanumerical(), + Set::of('é', 'è', 'ê', 'ë', '_'), + ) ->between(1, $max) ->filter(static fn($string) => \mb_strlen($string, 'ascii') < $max) ->map(Model::of(...)); diff --git a/fixtures/Table/Column/Type.php b/fixtures/Table/Column/Type.php index 1f906e0..51d7872 100644 --- a/fixtures/Table/Column/Type.php +++ b/fixtures/Table/Column/Type.php @@ -13,7 +13,7 @@ final class Type */ public static function any(): Set { - return Set\Either::any( + return Set::either( self::bigint(), self::binary(), self::bit(), @@ -28,7 +28,7 @@ public static function any(): Set self::nullable(), self::comment(), self::nullable(self::comment()), - Set\Elements::of(Model::uuid(), Model::bool()), + Set::of(Model::uuid(), Model::bool()), ); } @@ -37,7 +37,7 @@ public static function any(): Set */ public static function constraint(): Set { - return Set\Either::any( + return Set::either( self::bigint(), self::binary(), self::bit(), @@ -48,7 +48,7 @@ public static function constraint(): Set self::smallint(), self::tinyint(), self::varchar(), - Set\Elements::of(Model::uuid(), Model::bool()), + Set::of(Model::uuid(), Model::bool()), ); } @@ -57,7 +57,9 @@ public static function constraint(): Set */ private static function bigint(): Set { - return Set\Integers::between(1, 255)->map(Model::bigint(...)); + return Set::integers() + ->between(1, 255) + ->map(Model::bigint(...)); } /** @@ -65,7 +67,9 @@ private static function bigint(): Set */ private static function binary(): Set { - return Set\Integers::between(1, 255)->map(Model::binary(...)); + return Set::integers() + ->between(1, 255) + ->map(Model::binary(...)); } /** @@ -73,7 +77,9 @@ private static function binary(): Set */ private static function bit(): Set { - return Set\Integers::between(1, 64)->map(Model::bit(...)); + return Set::integers() + ->between(1, 64) + ->map(Model::bit(...)); } /** @@ -81,7 +87,9 @@ private static function bit(): Set */ private static function char(): Set { - return Set\Integers::between(1, 255)->map(Model::char(...)); + return Set::integers() + ->between(1, 255) + ->map(Model::char(...)); } /** @@ -89,12 +97,14 @@ private static function char(): Set */ private static function decimal(): Set { - return Set\Either::any( - Set\Integers::between(1, 65)->map(Model::decimal(...)), - Set\Composite::immutable( + return Set::either( + Set::integers() + ->between(1, 65) + ->map(Model::decimal(...)), + Set::compose( static fn($precision, $scale) => [$precision, $scale], - Set\Integers::between(1, 65), - Set\Integers::between(0, 30), + Set::integers()->between(1, 65), + Set::integers()->between(0, 30), ) ->filter(static fn($precision) => $precision[1] <= $precision[0]) // scale can't be higher than the precision ->map(static fn($precision) => Model::decimal(...$precision)), @@ -106,7 +116,9 @@ private static function decimal(): Set */ private static function int(): Set { - return Set\Integers::between(1, 255)->map(Model::int(...)); + return Set::integers() + ->between(1, 255) + ->map(Model::int(...)); } /** @@ -114,7 +126,9 @@ private static function int(): Set */ private static function mediumint(): Set { - return Set\Integers::between(1, 255)->map(Model::mediumint(...)); + return Set::integers() + ->between(1, 255) + ->map(Model::mediumint(...)); } /** @@ -122,7 +136,9 @@ private static function mediumint(): Set */ private static function smallint(): Set { - return Set\Integers::between(1, 255)->map(Model::smallint(...)); + return Set::integers() + ->between(1, 255) + ->map(Model::smallint(...)); } /** @@ -130,7 +146,9 @@ private static function smallint(): Set */ private static function tinyint(): Set { - return Set\Integers::between(1, 255)->map(Model::tinyint(...)); + return Set::integers() + ->between(1, 255) + ->map(Model::tinyint(...)); } /** @@ -138,7 +156,9 @@ private static function tinyint(): Set */ private static function varchar(): Set { - return Set\Integers::between(1, 255)->map(Model::varchar(...)); + return Set::integers() + ->between(1, 255) + ->map(Model::varchar(...)); } /** @@ -146,30 +166,27 @@ private static function varchar(): Set */ private static function of(): Set { - return Set\Decorate::immutable( - static fn(string $name): Model => Model::$name(), - Set\Elements::of( - 'bigint', - 'binary', - 'bit', - 'blob', - 'char', - 'date', - 'datetime', - 'decimal', - 'double', - 'float', - 'int', - 'json', - 'longtext', - 'mediumint', - 'mediumtext', - 'smallint', - 'text', - 'tinyint', - 'varchar', - ), - ); + return Set::of( + 'bigint', + 'binary', + 'bit', + 'blob', + 'char', + 'date', + 'datetime', + 'decimal', + 'double', + 'float', + 'int', + 'json', + 'longtext', + 'mediumint', + 'mediumtext', + 'smallint', + 'text', + 'tinyint', + 'varchar', + )->map(static fn(string $name): Model => Model::$name()); } /** @@ -177,9 +194,8 @@ private static function of(): Set */ private static function nullable(?Set $set = null): Set { - return Set\Decorate::immutable( + return ($set ?? self::of())->map( static fn(Model $type): Model => $type->nullable(), - $set ?? self::of(), ); } @@ -188,10 +204,12 @@ private static function nullable(?Set $set = null): Set */ private static function comment(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(Model $type, string $comment): Model => $type->comment($comment), self::of(), - Set\Strings::madeOf(Set\Chars::alphanumerical())->atLeast(1), - ); + Set::strings() + ->madeOf(Set::strings()->chars()->alphanumerical()) + ->atLeast(1), + )->toSet(); } } diff --git a/fixtures/Table/Name.php b/fixtures/Table/Name.php index 34dbd46..abe7412 100644 --- a/fixtures/Table/Name.php +++ b/fixtures/Table/Name.php @@ -13,17 +13,19 @@ final class Name */ public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(string $firstChar, string $name): Model => Model::of($firstChar.$name), - Set\Either::any( // table name can't start with a number - Set\Chars::lowercaseLetter(), - Set\Chars::uppercaseLetter(), + Set::either( // table name can't start with a number + Set::strings()->chars()->lowercaseLetter(), + Set::strings()->chars()->uppercaseLetter(), ), - Set\Strings::madeOf( - Set\Chars::alphanumerical(), - Set\Elements::of('é', 'è', 'ê', 'ë', '_'), - )->between(0, 63), - ); + Set::strings() + ->madeOf( + Set::strings()->chars()->alphanumerical(), + Set::of('é', 'è', 'ê', 'ë', '_'), + ) + ->between(0, 63), + )->toSet(); } /** @@ -31,7 +33,7 @@ public static function any(): Set */ public static function pair(): Set { - return Set\Composite::immutable( + return Set::compose( static fn($a, $b) => [$a, $b], self::any(), self::any(), diff --git a/proofs/connection/lazy.php b/proofs/connection/lazy.php index e4d43f0..de2dbe4 100644 --- a/proofs/connection/lazy.php +++ b/proofs/connection/lazy.php @@ -1,22 +1,16 @@ PDO::of(Url::of("mysql://root:root@127.0.0.1:$port/example")), - ); + $connection = Connection::new(Url::of("mysql://root:root@127.0.0.1:$port/example"))->unwrap(); Properties::seed($connection); - $connections = Set\Call::of(static function() use ($connection) { + $connections = Set::call(static function() use ($connection) { Properties::seed($connection); return $connection; @@ -32,8 +26,7 @@ yield test( 'Lazy connection must not be established at instanciation', static fn($assert) => $assert - ->object(Lazy::of(static fn() => PDO::of(Url::of('mysql://unknown:unknown@127.0.0.1:3306/unknown')))) - ->instance(Connection::class), + ->object(Connection::new(Url::of('mysql://unknown:unknown@127.0.0.1:3306/unknown'))), ); yield properties( diff --git a/proofs/connection/logger.php b/proofs/connection/logger.php index a6eb4e7..5fcb12d 100644 --- a/proofs/connection/logger.php +++ b/proofs/connection/logger.php @@ -1,11 +1,7 @@ unwrap(), new NullLogger, ); Properties::seed($connection); - $connections = Set\Call::of(static function() use ($connection) { + $connections = Set::call(static function() use ($connection) { Properties::seed($connection); return $connection; diff --git a/proofs/connection/pdo.php b/proofs/connection/pdo.php index ac566fe..673e2fb 100644 --- a/proofs/connection/pdo.php +++ b/proofs/connection/pdo.php @@ -4,7 +4,6 @@ use Formal\AccessLayer\{ Connection, - Connection\PDO, Query\CreateTable, Query\Constraint\ForeignKey, Query\Delete, @@ -32,21 +31,13 @@ use Innmind\BlackBox\Set; $proofs = static function(Url $dsn, Driver $driver) { - $connection = PDO::of($dsn); - $persistent = PDO::persistent($dsn); + $connection = Connection::new($dsn)->unwrap(); Properties::seed($connection); - $connections = Set\Either::any( - Set\Call::of(static function() use ($connection) { - Properties::seed($connection); + $connections = Set::call(static function() use ($connection) { + Properties::seed($connection); - return $connection; - }), - Set\Call::of(static function() use ($persistent) { - Properties::seed($persistent); - - return $persistent; - }), - ); + return $connection; + }); yield test( "PDO interface({$driver->name})", @@ -55,7 +46,7 @@ ->instance(Connection::class), ); - $lazy = static fn($connection) => test( + yield test( "PDO lazy select doesnt load everything in memory({$driver->name})", static function($assert) use ($connection) { $table = Table\Name::of('test_lazy_load'); @@ -99,9 +90,6 @@ static function($assert) use ($connection) { }, ); - yield $lazy($connection); - yield $lazy($persistent); - if ($driver === Driver::mysql) { yield test( "PDO charset({$driver->name})", @@ -125,7 +113,7 @@ static function($assert) use ($connection, $dsn) { $select = Select::from($table); - $ascii = PDO::of($dsn->withQuery(Query::of('charset=ascii'))); + $ascii = Connection::new($dsn->withQuery(Query::of('charset=ascii')))->unwrap(); $assert ->expected('gelé') ->not() @@ -139,7 +127,7 @@ static function($assert) use ($connection, $dsn) { ), ); - $utf8 = PDO::of($dsn->withQuery(Query::of('charset=utf8mb4'))); + $utf8 = Connection::new($dsn->withQuery(Query::of('charset=utf8mb4')))->unwrap(); $assert->same( 'gelé', $utf8($select) @@ -314,7 +302,7 @@ static function($assert) use ($connection) { $connection(Delete::from($parent)); $rows = $connection(Select::from($child)); - $assert->count(0, $rows); + $assert->same(0, $rows->size()); $connection(DropTable::named($child)); $connection(DropTable::named($parent)); @@ -467,10 +455,10 @@ static function($assert) use ($connection) { ); $rows = $connection(Select::from($child)); - $assert->count(1, $rows); + $assert->same(1, $rows->size()); $rows = $connection(Select::from($parent)); - $assert->count(0, $rows); + $assert->same(0, $rows->size()); $connection(DropTable::named($parent->name())); $connection(DropTable::named($child->name())); @@ -479,7 +467,7 @@ static function($assert) use ($connection) { yield proof( "Unique constraint({$driver->name})", - given(Set\Integers::between(0, 1_000_000)), + given(Set::integers()->between(0, 1_000_000)), static function($assert, $int) use ($connection) { $table = Table\Name::of('test_unique'); $connection(CreateTable::ifNotExists( diff --git a/proofs/query/parameter/type.php b/proofs/query/parameter/type.php index 0546baa..4978230 100644 --- a/proofs/query/parameter/type.php +++ b/proofs/query/parameter/type.php @@ -31,7 +31,7 @@ static function($assert) { yield proof( 'Type::for() int', - given(Set\Integers::any()), + given(Set::integers()), static function($assert, $int) { $assert->same( Type::int, @@ -42,7 +42,7 @@ static function($assert, $int) { yield proof( 'Type::for() string', - given(Set\Unicode::strings()), + given(Set::strings()->unicode()), static function($assert, $string) { $assert->same( Type::string, @@ -54,7 +54,7 @@ static function($assert, $string) { yield proof( 'Type::for() unsupported data', given( - Set\Elements::of( + Set::of( new \stdClass, new class {}, static fn() => null, diff --git a/proofs/query/where.php b/proofs/query/where.php index 24aa1ea..52e6c11 100644 --- a/proofs/query/where.php +++ b/proofs/query/where.php @@ -23,9 +23,10 @@ static function($assert) { $where = Where::of(null); + [$sql, $parameters] = $where->normalize(Driver::mysql); $assert->object($where)->instance(Where::class); - $assert->same('', $where->sql(Driver::mysql)); - $assert->count(0, $where->parameters()); + $assert->same('', $sql); + $assert->same(0, $parameters->size()); }, ); @@ -33,7 +34,7 @@ static function($assert) { 'Where equal comparator', given( Column::any(), - Set\Strings::any(), + Set::strings(), ), static function($assert, $column, $value) { $specification = Property::of( @@ -43,12 +44,13 @@ static function($assert, $column, $value) { ); $where = Where::of($specification); + [$sql, $parameters] = $where->normalize(Driver::mysql); $assert->same( "WHERE {$column->name()->sql(Driver::mysql)} = ?", - $where->sql(Driver::mysql), + $sql, ); - $assert->count(1, $where->parameters()); - $assert->same($value, $where->parameters()->first()->match( + $assert->same(1, $parameters->size()); + $assert->same($value, $parameters->first()->match( static fn($parameter) => $parameter->value(), static fn() => null, )); @@ -59,7 +61,7 @@ static function($assert, $column, $value) { 'Where less than comparator', given( Column::any(), - Set\Strings::any(), + Set::strings(), ), static function($assert, $column, $value) { $specification = Property::of( @@ -69,12 +71,13 @@ static function($assert, $column, $value) { ); $where = Where::of($specification); + [$sql, $parameters] = $where->normalize(Driver::mysql); $assert->same( "WHERE {$column->name()->sql(Driver::mysql)} < ?", - $where->sql(Driver::mysql), + $sql, ); - $assert->count(1, $where->parameters()); - $assert->same($value, $where->parameters()->first()->match( + $assert->same(1, $parameters->size()); + $assert->same($value, $parameters->first()->match( static fn($parameter) => $parameter->value(), static fn() => null, )); @@ -85,7 +88,7 @@ static function($assert, $column, $value) { 'Where less than or equal comparator', given( Column::any(), - Set\Strings::any(), + Set::strings(), ), static function($assert, $column, $value) { $lessThan = Property::of( @@ -100,12 +103,13 @@ static function($assert, $column, $value) { ); $where = Where::of($lessThan->or($equal)); + [$sql, $parameters] = $where->normalize(Driver::mysql); $assert->same( "WHERE {$column->name()->sql(Driver::mysql)} <= ?", - $where->sql(Driver::mysql), + $sql, ); - $assert->count(1, $where->parameters()); - $assert->same($value, $where->parameters()->first()->match( + $assert->same(1, $parameters->size()); + $assert->same($value, $parameters->first()->match( static fn($parameter) => $parameter->value(), static fn() => null, )); @@ -117,7 +121,7 @@ static function($assert, $column, $value) { given( Column::any(), Column::any(), - Set\Strings::any(), + Set::strings(), ), static function($assert, $column1, $column2, $value) { $lessThan = Property::of( @@ -131,17 +135,18 @@ static function($assert, $column1, $column2, $value) { $value, ); $where = Where::of($lessThan->or($equal)); + [$sql, $parameters] = $where->normalize(Driver::mysql); $assert->same( "WHERE ({$column1->name()->sql(Driver::mysql)} < ? OR {$column2->name()->sql(Driver::mysql)} = ?)", - $where->sql(Driver::mysql), + $sql, ); - $assert->count(2, $where->parameters()); - $assert->same($value, $where->parameters()->first()->match( + $assert->same(2, $parameters->size()); + $assert->same($value, $parameters->first()->match( static fn($parameter) => $parameter->value(), static fn() => null, )); - $assert->same($value, $where->parameters()->last()->match( + $assert->same($value, $parameters->last()->match( static fn($parameter) => $parameter->value(), static fn() => null, )); @@ -152,7 +157,7 @@ static function($assert, $column1, $column2, $value) { 'Where more than comparator', given( Column::any(), - Set\Strings::any(), + Set::strings(), ), static function($assert, $column, $value) { $specification = Property::of( @@ -162,12 +167,13 @@ static function($assert, $column, $value) { ); $where = Where::of($specification); + [$sql, $parameters] = $where->normalize(Driver::mysql); $assert->same( "WHERE {$column->name()->sql(Driver::mysql)} > ?", - $where->sql(Driver::mysql), + $sql, ); - $assert->count(1, $where->parameters()); - $assert->same($value, $where->parameters()->first()->match( + $assert->same(1, $parameters->size()); + $assert->same($value, $parameters->first()->match( static fn($parameter) => $parameter->value(), static fn() => null, )); @@ -178,7 +184,7 @@ static function($assert, $column, $value) { 'Where more than or equal comparator', given( Column::any(), - Set\Strings::any(), + Set::strings(), ), static function($assert, $column, $value) { $moreThan = Property::of( @@ -193,12 +199,13 @@ static function($assert, $column, $value) { ); $where = Where::of($moreThan->or($equal)); + [$sql, $parameters] = $where->normalize(Driver::mysql); $assert->same( "WHERE {$column->name()->sql(Driver::mysql)} >= ?", - $where->sql(Driver::mysql), + $sql, ); - $assert->count(1, $where->parameters()); - $assert->same($value, $where->parameters()->first()->match( + $assert->same(1, $parameters->size()); + $assert->same($value, $parameters->first()->match( static fn($parameter) => $parameter->value(), static fn() => null, )); @@ -210,7 +217,7 @@ static function($assert, $column, $value) { given( Column::any(), Column::any(), - Set\Strings::any(), + Set::strings(), ), static function($assert, $column1, $column2, $value) { $moreThan = Property::of( @@ -225,16 +232,17 @@ static function($assert, $column1, $column2, $value) { ); $where = Where::of($moreThan->or($equal)); + [$sql, $parameters] = $where->normalize(Driver::mysql); $assert->same( "WHERE ({$column1->name()->sql(Driver::mysql)} > ? OR {$column2->name()->sql(Driver::mysql)} = ?)", - $where->sql(Driver::mysql), + $sql, ); - $assert->count(2, $where->parameters()); - $assert->same($value, $where->parameters()->first()->match( + $assert->same(2, $parameters->size()); + $assert->same($value, $parameters->first()->match( static fn($parameter) => $parameter->value(), static fn() => null, )); - $assert->same($value, $where->parameters()->last()->match( + $assert->same($value, $parameters->last()->match( static fn($parameter) => $parameter->value(), static fn() => null, )); @@ -252,11 +260,12 @@ static function($assert, $column) { ); $where = Where::of($specification); + [$sql, $parameters] = $where->normalize(Driver::mysql); $assert->same( "WHERE {$column->name()->sql(Driver::mysql)} IS NULL", - $where->sql(Driver::mysql), + $sql, ); - $assert->count(0, $where->parameters()); + $assert->same(0, $parameters->size()); }, ); @@ -271,11 +280,12 @@ static function($assert, $column) { ); $where = Where::of($specification->not()); + [$sql, $parameters] = $where->normalize(Driver::mysql); $assert->same( "WHERE {$column->name()->sql(Driver::mysql)} IS NOT NULL", - $where->sql(Driver::mysql), + $sql, ); - $assert->count(0, $where->parameters()); + $assert->same(0, $parameters->size()); }, ); @@ -283,12 +293,12 @@ static function($assert, $column) { 'Where in comparator', given( Column::any(), - Set\Strings::any(), - Set\Strings::any(), - Set\Strings::any(), - Set\Sequence::of( - Set\Strings::any(), - Set\Integers::between(1, 5), + Set::strings(), + Set::strings(), + Set::strings(), + Set::sequence( + Set::strings(), + Set::integers()->between(1, 5), ), ), static function($assert, $column, $value1, $value2, $value3, $values) { @@ -299,20 +309,21 @@ static function($assert, $column, $value1, $value2, $value3, $values) { ); $where = Where::of($specification); + [$sql, $parameters] = $where->normalize(Driver::mysql); $assert->same( "WHERE {$column->name()->sql(Driver::mysql)} IN (?, ?, ?)", - $where->sql(Driver::mysql), + $sql, ); - $assert->count(3, $where->parameters()); - $assert->same($value1, $where->parameters()->get(0)->match( + $assert->same(3, $parameters->size()); + $assert->same($value1, $parameters->get(0)->match( static fn($parameter) => $parameter->value(), static fn() => null, )); - $assert->same($value2, $where->parameters()->get(1)->match( + $assert->same($value2, $parameters->get(1)->match( static fn($parameter) => $parameter->value(), static fn() => null, )); - $assert->same($value3, $where->parameters()->get(2)->match( + $assert->same($value3, $parameters->get(2)->match( static fn($parameter) => $parameter->value(), static fn() => null, )); @@ -324,11 +335,12 @@ static function($assert, $column, $value1, $value2, $value3, $values) { ); $where = Where::of($specification); + [$sql, $parameters] = $where->normalize(Driver::mysql); $assert->same( \count($values), - \count_chars($where->sql(Driver::mysql))[63], // looking for '?' placeholders + \count_chars($sql)[63], // looking for '?' placeholders ); - $assert->count(\count($values), $where->parameters()); + $assert->same(\count($values), $parameters->size()); }, ); @@ -336,8 +348,8 @@ static function($assert, $column, $value1, $value2, $value3, $values) { 'Where not', given( Column::any(), - Set\Strings::any(), - Set\Strings::any(), + Set::strings(), + Set::strings(), ), static function($assert, $column, $leftValue, $rightValue){ $specification = Property::of( @@ -347,12 +359,13 @@ static function($assert, $column, $leftValue, $rightValue){ ); $where = Where::of($specification->not()); + [$sql, $parameters] = $where->normalize(Driver::mysql); $assert->same( "WHERE {$column->name()->sql(Driver::mysql)} <> ?", - $where->sql(Driver::mysql), + $sql, ); - $assert->count(1, $where->parameters()); - $assert->same($leftValue, $where->parameters()->first()->match( + $assert->same(1, $parameters->size()); + $assert->same($leftValue, $parameters->first()->match( static fn($parameter) => $parameter->value(), static fn() => null, )); @@ -370,16 +383,17 @@ static function($assert, $column, $leftValue, $rightValue){ $specification = $left->or($right); $where = Where::of($specification->not()); + [$sql, $parameters] = $where->normalize(Driver::mysql); $assert->same( "WHERE NOT(({$column->name()->sql(Driver::mysql)} = ? OR {$column->name()->sql(Driver::mysql)} = ?))", - $where->sql(Driver::mysql), + $sql, ); - $assert->count(2, $where->parameters()); - $assert->same($leftValue, $where->parameters()->get(0)->match( + $assert->same(2, $parameters->size()); + $assert->same($leftValue, $parameters->get(0)->match( static fn($parameter) => $parameter->value(), static fn() => null, )); - $assert->same($rightValue, $where->parameters()->get(1)->match( + $assert->same($rightValue, $parameters->get(1)->match( static fn($parameter) => $parameter->value(), static fn() => null, )); @@ -391,8 +405,8 @@ static function($assert, $column, $leftValue, $rightValue){ given( Column::any(), Column::any(), - Set\Strings::any(), - Set\Strings::any(), + Set::strings(), + Set::strings(), ), static function($assert, $column1, $column2, $value1, $value2) { $left = Property::of( @@ -408,16 +422,17 @@ static function($assert, $column1, $column2, $value1, $value2) { $specification = $left->and($right->not()); $where = Where::of($specification); + [$sql, $parameters] = $where->normalize(Driver::mysql); $assert->same( "WHERE ({$column1->name()->sql(Driver::mysql)} = ? AND {$column2->name()->sql(Driver::mysql)} <> ?)", - $where->sql(Driver::mysql), + $sql, ); - $assert->count(2, $where->parameters()); - $assert->same($value1, $where->parameters()->first()->match( + $assert->same(2, $parameters->size()); + $assert->same($value1, $parameters->first()->match( static fn($parameter) => $parameter->value(), static fn() => null, )); - $assert->same($value2, $where->parameters()->last()->match( + $assert->same($value2, $parameters->last()->match( static fn($parameter) => $parameter->value(), static fn() => null, )); @@ -435,16 +450,17 @@ static function($assert, $column1, $column2, $value1, $value2) { $specification = $left->not()->and($right); $where = Where::of($specification); + [$sql, $parameters] = $where->normalize(Driver::mysql); $assert->same( "WHERE ({$column1->name()->sql(Driver::mysql)} <> ? AND {$column2->name()->sql(Driver::mysql)} = ?)", - $where->sql(Driver::mysql), + $sql, ); - $assert->count(2, $where->parameters()); - $assert->same($value1, $where->parameters()->first()->match( + $assert->same(2, $parameters->size()); + $assert->same($value1, $parameters->first()->match( static fn($parameter) => $parameter->value(), static fn() => null, )); - $assert->same($value2, $where->parameters()->last()->match( + $assert->same($value2, $parameters->last()->match( static fn($parameter) => $parameter->value(), static fn() => null, )); @@ -456,8 +472,8 @@ static function($assert, $column1, $column2, $value1, $value2) { given( Column::any(), Column::any(), - Set\Strings::any(), - Set\Strings::any(), + Set::strings(), + Set::strings(), ), static function($assert, $column1, $column2, $value1, $value2) { $left = Property::of( @@ -473,16 +489,17 @@ static function($assert, $column1, $column2, $value1, $value2) { $specification = $left->or($right->not()); $where = Where::of($specification); + [$sql, $parameters] = $where->normalize(Driver::mysql); $assert->same( "WHERE ({$column1->name()->sql(Driver::mysql)} = ? OR {$column2->name()->sql(Driver::mysql)} <> ?)", - $where->sql(Driver::mysql), + $sql, ); - $assert->count(2, $where->parameters()); - $assert->same($value1, $where->parameters()->first()->match( + $assert->same(2, $parameters->size()); + $assert->same($value1, $parameters->first()->match( static fn($parameter) => $parameter->value(), static fn() => null, )); - $assert->same($value2, $where->parameters()->last()->match( + $assert->same($value2, $parameters->last()->match( static fn($parameter) => $parameter->value(), static fn() => null, )); @@ -500,16 +517,17 @@ static function($assert, $column1, $column2, $value1, $value2) { $specification = $left->not()->or($right); $where = Where::of($specification); + [$sql, $parameters] = $where->normalize(Driver::mysql); $assert->same( "WHERE ({$column1->name()->sql(Driver::mysql)} <> ? OR {$column2->name()->sql(Driver::mysql)} = ?)", - $where->sql(Driver::mysql), + $sql, ); - $assert->count(2, $where->parameters()); - $assert->same($value1, $where->parameters()->first()->match( + $assert->same(2, $parameters->size()); + $assert->same($value1, $parameters->first()->match( static fn($parameter) => $parameter->value(), static fn() => null, )); - $assert->same($value2, $where->parameters()->last()->match( + $assert->same($value2, $parameters->last()->match( static fn($parameter) => $parameter->value(), static fn() => null, )); @@ -521,8 +539,8 @@ static function($assert, $column1, $column2, $value1, $value2) { given( Column::any(), Column::any(), - Set\Strings::any(), - Set\Elements::of( + Set::strings(), + Set::of( Type::bool, Type::null, Type::int, @@ -538,16 +556,17 @@ static function($assert, $column, $unused, $value, $type) { ); $where = Where::of($specification); + [$sql, $parameters] = $where->normalize(Driver::mysql); $assert->same( "WHERE {$column->name()->sql(Driver::mysql)} = ?", - $where->sql(Driver::mysql), + $sql, ); - $assert->count(1, $where->parameters()); - $assert->same($value, $where->parameters()->first()->match( + $assert->same(1, $parameters->size()); + $assert->same($value, $parameters->first()->match( static fn($parameter) => $parameter->value(), static fn() => null, )); - $assert->same($type, $where->parameters()->first()->match( + $assert->same($type, $parameters->first()->match( static fn($parameter) => $parameter->type(), static fn() => null, )); @@ -559,7 +578,7 @@ static function($assert, $column, $unused, $value, $type) { given( Name::any(), Column::any(), - Set\Strings::any(), + Set::strings(), ), static function($assert, $table, $column, $value) { $specification = Property::of( @@ -569,12 +588,13 @@ static function($assert, $table, $column, $value) { ); $where = Where::of($specification); + [$sql, $parameters] = $where->normalize(Driver::mysql); $assert->same( "WHERE {$table->sql(Driver::mysql)}.{$column->name()->sql(Driver::mysql)} = ?", - $where->sql(Driver::mysql), + $sql, ); - $assert->count(1, $where->parameters()); - $assert->same($value, $where->parameters()->first()->match( + $assert->same(1, $parameters->size()); + $assert->same($value, $parameters->first()->match( static fn($parameter) => $parameter->value(), static fn() => null, )); diff --git a/properties/Connection/AQueryWithoutTheCorrectNumberOfParametersMustThrow.php b/properties/Connection/AQueryWithoutTheCorrectNumberOfParametersMustThrow.php index 4533910..fe24f78 100644 --- a/properties/Connection/AQueryWithoutTheCorrectNumberOfParametersMustThrow.php +++ b/properties/Connection/AQueryWithoutTheCorrectNumberOfParametersMustThrow.php @@ -21,7 +21,7 @@ final class AQueryWithoutTheCorrectNumberOfParametersMustThrow implements Proper { public static function any(): Set { - return Set\Elements::of(new self); + return Set::of(new self); } public function applicableTo(object $connection): bool diff --git a/properties/Connection/AllowToStartTwoQueriesInParallel.php b/properties/Connection/AllowToStartTwoQueriesInParallel.php index 8f5f832..a415fec 100644 --- a/properties/Connection/AllowToStartTwoQueriesInParallel.php +++ b/properties/Connection/AllowToStartTwoQueriesInParallel.php @@ -34,12 +34,14 @@ private function __construct(string $uuid, string $name, int $number) public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), - Set\Uuid::any(), - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 125), - Set\Integers::any(), - ); + Set::uuid(), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 125), + Set::integers(), + )->toSet(); } public function applicableTo(object $connection): bool diff --git a/properties/Connection/AnInvalidLazyQueryMustThrow.php b/properties/Connection/AnInvalidLazyQueryMustThrow.php index 48699ff..c83e4f1 100644 --- a/properties/Connection/AnInvalidLazyQueryMustThrow.php +++ b/properties/Connection/AnInvalidLazyQueryMustThrow.php @@ -21,7 +21,7 @@ final class AnInvalidLazyQueryMustThrow implements Property { public static function any(): Set { - return Set\Elements::of(new self); + return Set::of(new self); } public function applicableTo(object $connection): bool diff --git a/properties/Connection/AnInvalidLazySelectMustThrow.php b/properties/Connection/AnInvalidLazySelectMustThrow.php index 08721b7..913d529 100644 --- a/properties/Connection/AnInvalidLazySelectMustThrow.php +++ b/properties/Connection/AnInvalidLazySelectMustThrow.php @@ -22,7 +22,7 @@ final class AnInvalidLazySelectMustThrow implements Property { public static function any(): Set { - return Set\Elements::of(new self); + return Set::of(new self); } public function applicableTo(object $connection): bool diff --git a/properties/Connection/AnInvalidQueryMustThrow.php b/properties/Connection/AnInvalidQueryMustThrow.php index 3b264d1..516adfa 100644 --- a/properties/Connection/AnInvalidQueryMustThrow.php +++ b/properties/Connection/AnInvalidQueryMustThrow.php @@ -21,7 +21,7 @@ final class AnInvalidQueryMustThrow implements Property { public static function any(): Set { - return Set\Elements::of(new self); + return Set::of(new self); } public function applicableTo(object $connection): bool diff --git a/properties/Connection/CanDropUnknownDatabaseIfNotExists.php b/properties/Connection/CanDropUnknownDatabaseIfNotExists.php index e8bbd47..ce916fc 100644 --- a/properties/Connection/CanDropUnknownDatabaseIfNotExists.php +++ b/properties/Connection/CanDropUnknownDatabaseIfNotExists.php @@ -40,7 +40,7 @@ public function ensureHeldBy(Assert $assert, object $connection): object { $rows = $connection(Query\DropTable::ifExists($this->name)); - $assert->count(0, $rows); + $assert->same(0, $rows->size()); return $connection; } diff --git a/properties/Connection/CommittingAnUnstartedTransactionMustThrow.php b/properties/Connection/CommittingAnUnstartedTransactionMustThrow.php index cde0025..7f25911 100644 --- a/properties/Connection/CommittingAnUnstartedTransactionMustThrow.php +++ b/properties/Connection/CommittingAnUnstartedTransactionMustThrow.php @@ -21,7 +21,7 @@ final class CommittingAnUnstartedTransactionMustThrow implements Property { public static function any(): Set { - return Set\Elements::of(new self); + return Set::of(new self); } public function applicableTo(object $connection): bool diff --git a/properties/Connection/ContentInsertedAfterStartOfTransactionIsAccessible.php b/properties/Connection/ContentInsertedAfterStartOfTransactionIsAccessible.php index 4f55d39..f6ca6d8 100644 --- a/properties/Connection/ContentInsertedAfterStartOfTransactionIsAccessible.php +++ b/properties/Connection/ContentInsertedAfterStartOfTransactionIsAccessible.php @@ -36,12 +36,14 @@ public function __construct(string $uuid, string $username, int $number) public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), - Set\Uuid::any(), - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 255), - Set\Integers::any(), - ); + Set::uuid(), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 255), + Set::integers(), + )->toSet(); } public function applicableTo(object $connection): bool @@ -64,7 +66,7 @@ public function ensureHeldBy(Assert $assert, object $connection): object $rows = $connection(SQL::of("SELECT * FROM test WHERE id = '{$this->uuid}'")); - $assert->count(1, $rows); + $assert->same(1, $rows->size()); $assert->same( $this->uuid, $rows diff --git a/properties/Connection/ContentIsAccessibleAfterCommit.php b/properties/Connection/ContentIsAccessibleAfterCommit.php index b86e4d1..efcd775 100644 --- a/properties/Connection/ContentIsAccessibleAfterCommit.php +++ b/properties/Connection/ContentIsAccessibleAfterCommit.php @@ -36,12 +36,14 @@ public function __construct(string $uuid, string $username, int $number) public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), - Set\Uuid::any(), - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 255), - Set\Integers::any(), - ); + Set::uuid(), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 255), + Set::integers(), + )->toSet(); } public function applicableTo(object $connection): bool @@ -66,7 +68,7 @@ public function ensureHeldBy(Assert $assert, object $connection): object $rows = $connection(SQL::of("SELECT * FROM test WHERE id = '{$this->uuid}'")); - $assert->count(1, $rows); + $assert->same(1, $rows->size()); $assert->same( $this->uuid, $rows diff --git a/properties/Connection/ContentIsNotAccessibleAfterRollback.php b/properties/Connection/ContentIsNotAccessibleAfterRollback.php index a936fbe..3032c84 100644 --- a/properties/Connection/ContentIsNotAccessibleAfterRollback.php +++ b/properties/Connection/ContentIsNotAccessibleAfterRollback.php @@ -36,12 +36,14 @@ public function __construct(string $uuid, string $username, int $number) public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), - Set\Uuid::any(), - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 255), - Set\Integers::any(), - ); + Set::uuid(), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 255), + Set::integers(), + )->toSet(); } public function applicableTo(object $connection): bool @@ -66,7 +68,7 @@ public function ensureHeldBy(Assert $assert, object $connection): object $rows = $connection(SQL::of("SELECT * FROM test WHERE id = '{$this->uuid}'")); - $assert->count(0, $rows); + $assert->same(0, $rows->size()); return $connection; } diff --git a/properties/Connection/CreateTable.php b/properties/Connection/CreateTable.php index a9b7862..c4be730 100644 --- a/properties/Connection/CreateTable.php +++ b/properties/Connection/CreateTable.php @@ -33,11 +33,11 @@ public function __construct($name, array $columns) public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), Name::any(), Column::list(), - ); + )->toSet(); } public function applicableTo(object $connection): bool @@ -50,7 +50,7 @@ public function ensureHeldBy(Assert $assert, object $connection): object try { $rows = $connection(Query\CreateTable::named($this->name, ...$this->columns)); - $assert->count(0, $rows); + $assert->same(0, $rows->size()); } finally { $connection(Query\DropTable::ifExists($this->name)); } diff --git a/properties/Connection/CreateTableIfNotExists.php b/properties/Connection/CreateTableIfNotExists.php index 756d142..702b1a2 100644 --- a/properties/Connection/CreateTableIfNotExists.php +++ b/properties/Connection/CreateTableIfNotExists.php @@ -33,11 +33,11 @@ public function __construct($name, array $columns) public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), Name::any(), Column::list(), - ); + )->toSet(); } public function applicableTo(object $connection): bool @@ -51,7 +51,7 @@ public function ensureHeldBy(Assert $assert, object $connection): object $connection(Query\CreateTable::named($this->name, ...$this->columns)); $rows = $connection(Query\CreateTable::ifNotExists($this->name, ...$this->columns)); - $assert->count(0, $rows); + $assert->same(0, $rows->size()); } finally { $connection(Query\DropTable::ifExists($this->name)); } diff --git a/properties/Connection/CreateTableWithForeignKey.php b/properties/Connection/CreateTableWithForeignKey.php index d4ef7ac..a6dcf5a 100644 --- a/properties/Connection/CreateTableWithForeignKey.php +++ b/properties/Connection/CreateTableWithForeignKey.php @@ -40,12 +40,12 @@ public static function any(): Set { // max length of 30 for column names as combined can't be higher than 64 // as it's the limit of the created constraint name - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), Name::pair(), Column::any(Column\Type::constraint(), 30), Column::any(null, 30), - ); + )->toSet(); } public function applicableTo(object $connection): bool @@ -60,7 +60,7 @@ public function ensureHeldBy(Assert $assert, object $connection): object $create = $create->primaryKey($this->primaryKey->name()); $rows = $connection($create); - $assert->count(0, $rows); + $assert->same(0, $rows->size()); $create = Query\CreateTable::named($this->name2, ConcreteColumn::of( $this->foreignKey->name(), @@ -73,7 +73,7 @@ public function ensureHeldBy(Assert $assert, object $connection): object ); $rows = $connection($create); - $assert->count(0, $rows); + $assert->same(0, $rows->size()); } finally { $connection(Query\DropTable::ifExists($this->name2)); $connection(Query\DropTable::ifExists($this->name1)); diff --git a/properties/Connection/CreateTableWithPrimaryKey.php b/properties/Connection/CreateTableWithPrimaryKey.php index 4919b1a..4a34e3c 100644 --- a/properties/Connection/CreateTableWithPrimaryKey.php +++ b/properties/Connection/CreateTableWithPrimaryKey.php @@ -38,12 +38,12 @@ public function __construct($name, $primaryKey, array $columns) public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), Name::any(), Column::any(Column\Type::constraint()), Column::list(), - ); + )->toSet(); } public function applicableTo(object $connection): bool @@ -58,7 +58,7 @@ public function ensureHeldBy(Assert $assert, object $connection): object $create = $create->primaryKey($this->primaryKey->name()); $rows = $connection($create); - $assert->count(0, $rows); + $assert->same(0, $rows->size()); } finally { $connection(Query\DropTable::ifExists($this->name)); } diff --git a/properties/Connection/CreatingSameTableTwiceMustThrow.php b/properties/Connection/CreatingSameTableTwiceMustThrow.php index 00ad807..1e5ead6 100644 --- a/properties/Connection/CreatingSameTableTwiceMustThrow.php +++ b/properties/Connection/CreatingSameTableTwiceMustThrow.php @@ -34,11 +34,11 @@ public function __construct($name, array $columns) public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), Name::any(), Column::list(), - ); + )->toSet(); } public function applicableTo(object $connection): bool diff --git a/properties/Connection/Delete.php b/properties/Connection/Delete.php index 664b4ae..3aa09fa 100644 --- a/properties/Connection/Delete.php +++ b/properties/Connection/Delete.php @@ -30,7 +30,7 @@ public function __construct(string $uuid) public static function any(): Set { - return Set\Uuid::any()->map(static fn($uuid) => new self($uuid)); + return Set::uuid()->map(static fn($uuid) => new self($uuid)); } public function applicableTo(object $connection): bool @@ -52,11 +52,11 @@ public function ensureHeldBy(Assert $assert, object $connection): object $sequence = $connection(Query\Delete::from(Table\Name::of('test'))); - $assert->count(0, $sequence); + $assert->same(0, $sequence->size()); $rows = $connection($select); - $assert->count(0, $rows); + $assert->same(0, $rows->size()); return $connection; } diff --git a/properties/Connection/DeleteSpecificRow.php b/properties/Connection/DeleteSpecificRow.php index 48732cd..ef89ffa 100644 --- a/properties/Connection/DeleteSpecificRow.php +++ b/properties/Connection/DeleteSpecificRow.php @@ -38,11 +38,11 @@ public function __construct(string $uuid1, string $uuid2) public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), - Set\Uuid::any(), - Set\Uuid::any(), - ); + Set::uuid(), + Set::uuid(), + )->toSet(); } public function applicableTo(object $connection): bool @@ -80,15 +80,15 @@ public function ensureHeldBy(Assert $assert, object $connection): object ); $sequence = $connection($delete); - $assert->count(0, $sequence); + $assert->same(0, $sequence->size()); $rows = $connection(SQL::of("SELECT * FROM test WHERE id = '{$this->uuid1}'")); - $assert->count(0, $rows); + $assert->same(0, $rows->size()); $rows = $connection(SQL::of("SELECT * FROM test WHERE id = '{$this->uuid2}'")); - $assert->count(1, $rows); + $assert->same(1, $rows->size()); return $connection; } diff --git a/properties/Connection/DeleteWithAlias.php b/properties/Connection/DeleteWithAlias.php index 0097450..69bbfdc 100644 --- a/properties/Connection/DeleteWithAlias.php +++ b/properties/Connection/DeleteWithAlias.php @@ -30,7 +30,7 @@ public function __construct(string $uuid) public static function any(): Set { - return Set\Uuid::any()->map(static fn($uuid) => new self($uuid)); + return Set::uuid()->map(static fn($uuid) => new self($uuid)); } public function applicableTo(object $connection): bool @@ -54,11 +54,11 @@ public function ensureHeldBy(Assert $assert, object $connection): object Table\Name::of('test')->as('alias'), )); - $assert->count(0, $sequence); + $assert->same(0, $sequence->size()); $rows = $connection($select); - $assert->count(0, $rows); + $assert->same(0, $rows->size()); return $connection; } diff --git a/properties/Connection/Insert.php b/properties/Connection/Insert.php index 55a434b..ad54efa 100644 --- a/properties/Connection/Insert.php +++ b/properties/Connection/Insert.php @@ -30,7 +30,7 @@ public function __construct(string $uuid) public static function any(): Set { - return Set\Uuid::any()->map(static fn($uuid) => new self($uuid)); + return Set::uuid()->map(static fn($uuid) => new self($uuid)); } public function applicableTo(object $connection): bool @@ -43,7 +43,7 @@ public function ensureHeldBy(Assert $assert, object $connection): object $select = SQL::of("SELECT * FROM test WHERE id = '{$this->uuid}'"); $rows = $connection($select); - $assert->count(0, $rows); + $assert->same(0, $rows->size()); $sequence = $connection(Query\Insert::into( Table\Name::of('test'), @@ -54,11 +54,11 @@ public function ensureHeldBy(Assert $assert, object $connection): object ]), )); - $assert->count(0, $sequence); + $assert->same(0, $sequence->size()); $rows = $connection($select); - $assert->count(1, $rows); + $assert->same(1, $rows->size()); $assert->same( $this->uuid, $rows diff --git a/properties/Connection/InsertSelect.php b/properties/Connection/InsertSelect.php index 73de92f..004724f 100644 --- a/properties/Connection/InsertSelect.php +++ b/properties/Connection/InsertSelect.php @@ -35,13 +35,17 @@ private function __construct( public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), - Set\Uuid::any(), - Set\Strings::madeOf(Set\Chars::alphanumerical())->between(0, 100), - Set\Integers::any(), - Set\Strings::madeOf(Set\Chars::alphanumerical())->between(10, 100), // to avoid collisions - ); + Set::uuid(), + Set::strings() + ->madeOf(Set::strings()->chars()->alphanumerical()) + ->between(0, 100), + Set::integers(), + Set::strings() + ->madeOf(Set::strings()->chars()->alphanumerical()) + ->between(10, 100), // to avoid collisions + )->toSet(); } public function applicableTo(object $connection): bool @@ -54,7 +58,7 @@ public function ensureHeldBy(Assert $assert, object $connection): object $select = SQL::of("SELECT * FROM test_values WHERE id = '{$this->uuid}'"); $rows = $connection($select); - $assert->count(0, $rows); + $assert->same(0, $rows->size()); $sequence = $connection(Query\Insert::into( Table\Name::of('test'), @@ -65,7 +69,7 @@ public function ensureHeldBy(Assert $assert, object $connection): object ]), )); - $assert->count(0, $sequence); + $assert->same(0, $sequence->size()); $sequence = $connection(Query\Insert::into( Table\Name::of('test_values'), @@ -84,11 +88,11 @@ public function ensureHeldBy(Assert $assert, object $connection): object )), )); - $assert->count(0, $sequence); + $assert->same(0, $sequence->size()); $rows = $connection($select); - $assert->count(1, $rows); + $assert->same(1, $rows->size()); $assert->same( $this->uuid, $rows diff --git a/properties/Connection/MultipleInsertsAtOnce.php b/properties/Connection/MultipleInsertsAtOnce.php index a89c9e1..0c77929 100644 --- a/properties/Connection/MultipleInsertsAtOnce.php +++ b/properties/Connection/MultipleInsertsAtOnce.php @@ -48,15 +48,19 @@ public function __construct( public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), - Set\Uuid::any(), - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 255), - Set\Integers::any(), - Set\Uuid::any(), - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 255), - Set\Integers::any(), - ); + Set::uuid(), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 255), + Set::integers(), + Set::uuid(), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 255), + Set::integers(), + )->toSet(); } public function applicableTo(object $connection): bool @@ -69,7 +73,7 @@ public function ensureHeldBy(Assert $assert, object $connection): object $select = SQL::of("SELECT * FROM test WHERE id IN ('{$this->uuid1}', '{$this->uuid2}')"); $rows = $connection($select); - $assert->count(0, $rows); + $assert->same(0, $rows->size()); $insert = Query\MultipleInsert::into( Table\Name::of('test'), @@ -90,11 +94,11 @@ public function ensureHeldBy(Assert $assert, object $connection): object ]), ))); - $assert->count(0, $sequence); + $assert->same(0, $sequence->size()); $rows = $connection($select); - $assert->count(2, $rows); + $assert->same(2, $rows->size()); $assert ->expected( $rows diff --git a/properties/Connection/MustThrowWhenValueDoesntFitTheSchema.php b/properties/Connection/MustThrowWhenValueDoesntFitTheSchema.php index f46d7a2..76548ef 100644 --- a/properties/Connection/MustThrowWhenValueDoesntFitTheSchema.php +++ b/properties/Connection/MustThrowWhenValueDoesntFitTheSchema.php @@ -33,12 +33,14 @@ public function __construct(string $uuid, string $username, int $number) public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), - Set\Uuid::any(), - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 255), - Set\Integers::any(), - ); + Set::uuid(), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 255), + Set::integers(), + )->toSet(); } public function applicableTo(object $connection): bool diff --git a/properties/Connection/ParameterTypesCanBeSpecified.php b/properties/Connection/ParameterTypesCanBeSpecified.php index be8e5e6..36d8833 100644 --- a/properties/Connection/ParameterTypesCanBeSpecified.php +++ b/properties/Connection/ParameterTypesCanBeSpecified.php @@ -33,12 +33,14 @@ public function __construct(string $uuid, string $username, int $number) public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), - Set\Uuid::any(), - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 255), - Set\Integers::any(), - ); + Set::uuid(), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 255), + Set::integers(), + )->toSet(); } public function applicableTo(object $connection): bool @@ -56,7 +58,7 @@ public function ensureHeldBy(Assert $assert, object $connection): object $rows = $connection(SQL::of("SELECT * FROM test WHERE id = '{$this->uuid}'")); - $assert->count(1, $rows); + $assert->same(1, $rows->size()); $assert->same( $this->uuid, $rows diff --git a/properties/Connection/ParametersCanBeBoundByIndex.php b/properties/Connection/ParametersCanBeBoundByIndex.php index 1c011a5..048ad5b 100644 --- a/properties/Connection/ParametersCanBeBoundByIndex.php +++ b/properties/Connection/ParametersCanBeBoundByIndex.php @@ -32,12 +32,14 @@ public function __construct(string $uuid, string $username, int $number) public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), - Set\Uuid::any(), - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 255), - Set\Integers::any(), - ); + Set::uuid(), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 255), + Set::integers(), + )->toSet(); } public function applicableTo(object $connection): bool @@ -55,7 +57,7 @@ public function ensureHeldBy(Assert $assert, object $connection): object $rows = $connection(SQL::of("SELECT * FROM test WHERE id = '{$this->uuid}'")); - $assert->count(1, $rows); + $assert->same(1, $rows->size()); $assert->same( $this->uuid, $rows diff --git a/properties/Connection/ParametersCanBeBoundByName.php b/properties/Connection/ParametersCanBeBoundByName.php index 933eaa3..688e53d 100644 --- a/properties/Connection/ParametersCanBeBoundByName.php +++ b/properties/Connection/ParametersCanBeBoundByName.php @@ -32,12 +32,14 @@ public function __construct(string $uuid, string $username, int $number) public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), - Set\Uuid::any(), - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 255), - Set\Integers::any(), - ); + Set::uuid(), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 255), + Set::integers(), + )->toSet(); } public function applicableTo(object $connection): bool @@ -55,7 +57,7 @@ public function ensureHeldBy(Assert $assert, object $connection): object $rows = $connection(SQL::of("SELECT * FROM test WHERE id = '{$this->uuid}'")); - $assert->count(1, $rows); + $assert->same(1, $rows->size()); $assert->same( $this->uuid, $rows diff --git a/properties/Connection/RollbackingAnUnstartedTransactionMustThrow.php b/properties/Connection/RollbackingAnUnstartedTransactionMustThrow.php index 309a4d1..54c53e7 100644 --- a/properties/Connection/RollbackingAnUnstartedTransactionMustThrow.php +++ b/properties/Connection/RollbackingAnUnstartedTransactionMustThrow.php @@ -21,7 +21,7 @@ final class RollbackingAnUnstartedTransactionMustThrow implements Property { public static function any(): Set { - return Set\Elements::of(new self); + return Set::of(new self); } public function applicableTo(object $connection): bool diff --git a/properties/Connection/SelectAliasedColumns.php b/properties/Connection/SelectAliasedColumns.php index f147fbf..430dba8 100644 --- a/properties/Connection/SelectAliasedColumns.php +++ b/properties/Connection/SelectAliasedColumns.php @@ -35,12 +35,14 @@ public function __construct(string $uuid, string $username, int $number) public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), - Set\Uuid::any(), - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 255), - Set\Integers::any(), - ); + Set::uuid(), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 255), + Set::integers(), + )->toSet(); } public function applicableTo(object $connection): bool diff --git a/properties/Connection/SelectColumns.php b/properties/Connection/SelectColumns.php index 05e51c4..159beb1 100644 --- a/properties/Connection/SelectColumns.php +++ b/properties/Connection/SelectColumns.php @@ -35,12 +35,14 @@ public function __construct(string $uuid, string $username, int $number) public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), - Set\Uuid::any(), - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 255), - Set\Integers::any(), - ); + Set::uuid(), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 255), + Set::integers(), + )->toSet(); } public function applicableTo(object $connection): bool diff --git a/properties/Connection/SelectCount.php b/properties/Connection/SelectCount.php index b0e302b..282a7c7 100644 --- a/properties/Connection/SelectCount.php +++ b/properties/Connection/SelectCount.php @@ -37,13 +37,15 @@ public function __construct($name, string $uuid, string $username, int $number) public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), FName::any(), - Set\Uuid::any(), - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 255), - Set\Integers::any(), - ); + Set::uuid(), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 255), + Set::integers(), + )->toSet(); } public function applicableTo(object $connection): bool diff --git a/properties/Connection/SelectEverything.php b/properties/Connection/SelectEverything.php index d7851c4..3273b5f 100644 --- a/properties/Connection/SelectEverything.php +++ b/properties/Connection/SelectEverything.php @@ -34,12 +34,14 @@ public function __construct(string $uuid, string $username, int $number) public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), - Set\Uuid::any(), - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 255), - Set\Integers::any(), - ); + Set::uuid(), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 255), + Set::integers(), + )->toSet(); } public function applicableTo(object $connection): bool diff --git a/properties/Connection/SelectLimit.php b/properties/Connection/SelectLimit.php index 6296c91..c17b7ff 100644 --- a/properties/Connection/SelectLimit.php +++ b/properties/Connection/SelectLimit.php @@ -40,13 +40,15 @@ public function __construct( public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), - Set\Uuid::any(), - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 255), - Set\Integers::any(), - Set\Integers::above(1), - ); + Set::uuid(), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 255), + Set::integers(), + Set::integers()->above(1), + )->toSet(); } public function applicableTo(object $connection): bool diff --git a/properties/Connection/SelectOffset.php b/properties/Connection/SelectOffset.php index 2cc242a..493ae42 100644 --- a/properties/Connection/SelectOffset.php +++ b/properties/Connection/SelectOffset.php @@ -40,13 +40,15 @@ public function __construct( public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), - Set\Uuid::any(), - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 255), - Set\Integers::any(), - Set\Integers::above(1), - ); + Set::uuid(), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 255), + Set::integers(), + Set::integers()->above(1), + )->toSet(); } public function applicableTo(object $connection): bool diff --git a/properties/Connection/SelectOrder.php b/properties/Connection/SelectOrder.php index 52b72d7..026c29f 100644 --- a/properties/Connection/SelectOrder.php +++ b/properties/Connection/SelectOrder.php @@ -47,13 +47,15 @@ public function __construct( public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), - Set\Uuid::any(), - Set\Uuid::any(), - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 254), - Set\Integers::any(), - ); + Set::uuid(), + Set::uuid(), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 254), + Set::integers(), + )->toSet(); } public function applicableTo(object $connection): bool diff --git a/properties/Connection/SelectValues.php b/properties/Connection/SelectValues.php index 19d7d54..3d79902 100644 --- a/properties/Connection/SelectValues.php +++ b/properties/Connection/SelectValues.php @@ -38,18 +38,22 @@ private function __construct( public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), - Set\Uuid::any(), - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 255), - Set\Integers::any(), + Set::uuid(), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 255), + Set::integers(), FName::any(), - Set\Either::any( - Set\Integers::any(), - Set\Strings::madeOf(Set\Chars::alphanumerical()), - Set\Elements::of(null, true, false), + Set::either( + Set::integers(), + Set::strings()->madeOf( + Set::strings()->chars()->alphanumerical(), + ), + Set::of(null, true, false), ), - ); + )->toSet(); } public function applicableTo(object $connection): bool @@ -85,7 +89,7 @@ public function ensureHeldBy(Assert $assert, object $connection): object )); $rows = $connection($select); - $assert->count(1, $rows); + $assert->same(1, $rows->size()); $assert->same( $this->uuid, $rows diff --git a/properties/Connection/SelectWhere.php b/properties/Connection/SelectWhere.php index 07dde12..663d2b9 100644 --- a/properties/Connection/SelectWhere.php +++ b/properties/Connection/SelectWhere.php @@ -38,12 +38,14 @@ public function __construct(string $uuid, string $username, int $number) public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), - Set\Uuid::any(), - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 255), - Set\Integers::any(), - ); + Set::uuid(), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 255), + Set::integers(), + )->toSet(); } public function applicableTo(object $connection): bool @@ -70,7 +72,7 @@ public function ensureHeldBy(Assert $assert, object $connection): object )); $rows = $connection($select); - $assert->count(1, $rows); + $assert->same(1, $rows->size()); $assert->same( $this->uuid, $rows diff --git a/properties/Connection/SelectWhereContains.php b/properties/Connection/SelectWhereContains.php index 88fa80a..ce6f0ad 100644 --- a/properties/Connection/SelectWhereContains.php +++ b/properties/Connection/SelectWhereContains.php @@ -47,14 +47,20 @@ public function __construct( public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), - Set\Uuid::any(), - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 100), - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 100), - Set\Strings::madeOf(Set\Chars::ascii())->between(10, 55), // 10 to avoid collisions with possible other values - Set\Integers::any(), - ); + Set::uuid(), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 100), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 100), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(10, 55), // 10 to avoid collisions with possible other values + Set::integers(), + )->toSet(); } public function applicableTo(object $connection): bool @@ -81,7 +87,7 @@ public function ensureHeldBy(Assert $assert, object $connection): object )); $rows = $connection($select); - $assert->count(1, $rows); + $assert->same(1, $rows->size()); $assert->same( $this->uuid, $rows diff --git a/properties/Connection/SelectWhereEndsWith.php b/properties/Connection/SelectWhereEndsWith.php index dd4fea5..3eff0f6 100644 --- a/properties/Connection/SelectWhereEndsWith.php +++ b/properties/Connection/SelectWhereEndsWith.php @@ -44,13 +44,17 @@ public function __construct( public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), - Set\Uuid::any(), - Set\Strings::madeOf(Set\Chars::ascii())->between(10, 125), // 10 to avoid collisions with possible other values - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 125), - Set\Integers::any(), - ); + Set::uuid(), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(10, 125), // 10 to avoid collisions with possible other values + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 125), + Set::integers(), + )->toSet(); } public function applicableTo(object $connection): bool @@ -77,7 +81,7 @@ public function ensureHeldBy(Assert $assert, object $connection): object )); $rows = $connection($select); - $assert->count(1, $rows); + $assert->same(1, $rows->size()); $assert->same( $this->uuid, $rows diff --git a/properties/Connection/SelectWhereIn.php b/properties/Connection/SelectWhereIn.php index 1e335aa..c5d9cb8 100644 --- a/properties/Connection/SelectWhereIn.php +++ b/properties/Connection/SelectWhereIn.php @@ -38,12 +38,14 @@ public function __construct(string $uuid, string $username, int $number) public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), - Set\Uuid::any(), - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 255), - Set\Integers::any(), - ); + Set::uuid(), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 255), + Set::integers(), + )->toSet(); } public function applicableTo(object $connection): bool @@ -70,7 +72,7 @@ public function ensureHeldBy(Assert $assert, object $connection): object )); $rows = $connection($select); - $assert->count(1, $rows); + $assert->same(1, $rows->size()); $assert->same( $this->uuid, $rows diff --git a/properties/Connection/SelectWhereInQuery.php b/properties/Connection/SelectWhereInQuery.php index eb44dc4..1b76e5c 100644 --- a/properties/Connection/SelectWhereInQuery.php +++ b/properties/Connection/SelectWhereInQuery.php @@ -49,17 +49,23 @@ public function __construct( public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), - Set\Uuid::any(), - Set\Uuid::any(), - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 255), - Set\Integers::any(), + Set::uuid(), + Set::uuid(), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 255), + Set::integers(), Set\MutuallyExclusive::of( - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 255), - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 255), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 255), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 255), ), - ); + )->toSet(); } public function applicableTo(object $connection): bool @@ -100,7 +106,7 @@ public function ensureHeldBy(Assert $assert, object $connection): object )); $rows = $connection($select); - $assert->count(1, $rows); + $assert->same(1, $rows->size()); $assert->same( $this->uuid1, $rows diff --git a/properties/Connection/SelectWhereStartsWith.php b/properties/Connection/SelectWhereStartsWith.php index 34eecf7..64d4724 100644 --- a/properties/Connection/SelectWhereStartsWith.php +++ b/properties/Connection/SelectWhereStartsWith.php @@ -44,13 +44,17 @@ public function __construct( public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), - Set\Uuid::any(), - Set\Strings::madeOf(Set\Chars::ascii())->between(10, 125), // 10 to avoid collisions with possible other values - Set\Strings::madeOf(Set\Chars::ascii())->between(0, 125), - Set\Integers::any(), - ); + Set::uuid(), + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(10, 125), // 10 to avoid collisions with possible other values + Set::strings() + ->madeOf(Set::strings()->chars()->ascii()) + ->between(0, 125), + Set::integers(), + )->toSet(); } public function applicableTo(object $connection): bool @@ -77,7 +81,7 @@ public function ensureHeldBy(Assert $assert, object $connection): object )); $rows = $connection($select); - $assert->count(1, $rows); + $assert->same(1, $rows->size()); $assert->same( $this->uuid, $rows diff --git a/properties/Connection/Update.php b/properties/Connection/Update.php index 2265c00..e4da382 100644 --- a/properties/Connection/Update.php +++ b/properties/Connection/Update.php @@ -30,7 +30,7 @@ public function __construct(string $uuid) public static function any(): Set { - return Set\Uuid::any()->map(static fn($uuid) => new self($uuid)); + return Set::uuid()->map(static fn($uuid) => new self($uuid)); } public function applicableTo(object $connection): bool @@ -55,7 +55,7 @@ public function ensureHeldBy(Assert $assert, object $connection): object Row::of(['registerNumber' => 24]), )); - $assert->count(0, $sequence); + $assert->same(0, $sequence->size()); $rows = $connection($select); diff --git a/properties/Connection/UpdateSpecificRow.php b/properties/Connection/UpdateSpecificRow.php index 3b8bcba..00f1c87 100644 --- a/properties/Connection/UpdateSpecificRow.php +++ b/properties/Connection/UpdateSpecificRow.php @@ -38,11 +38,11 @@ public function __construct(string $uuid1, string $uuid2) public static function any(): Set { - return Set\Composite::immutable( + return Set::compose( static fn(...$args) => new self(...$args), - Set\Uuid::any(), - Set\Uuid::any(), - ); + Set::uuid(), + Set::uuid(), + )->toSet(); } public function applicableTo(object $connection): bool @@ -82,11 +82,11 @@ public function ensureHeldBy(Assert $assert, object $connection): object )); $sequence = $connection($update); - $assert->count(0, $sequence); + $assert->same(0, $sequence->size()); $rows = $connection(SQL::of("SELECT * FROM test WHERE id = '{$this->uuid1}'")); - $assert->count(1, $rows); + $assert->same(1, $rows->size()); $assert->same( 24, $rows @@ -100,7 +100,7 @@ public function ensureHeldBy(Assert $assert, object $connection): object $rows = $connection(SQL::of("SELECT * FROM test WHERE id = '{$this->uuid2}'")); - $assert->count(1, $rows); + $assert->same(1, $rows->size()); $assert->same( 42, $rows diff --git a/src/Connection.php b/src/Connection.php index c026595..d777920 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -3,15 +3,51 @@ namespace Formal\AccessLayer; -use Formal\AccessLayer\Exception\QueryFailed; -use Innmind\Immutable\Sequence; +use Formal\AccessLayer\{ + Connection\Implementation, + Connection\PDO, + Connection\Logger, + Exception\QueryFailed, +}; +use Innmind\Url\Url; +use Innmind\Immutable\{ + Sequence, + Attempt, +}; +use Psr\Log\LoggerInterface; -interface Connection +final class Connection { + private function __construct( + private Implementation $implementation, + ) { + } + /** * @throws QueryFailed * * @return Sequence */ - public function __invoke(Query $query): Sequence; + public function __invoke(Query|Query\Builder $query): Sequence + { + return ($this->implementation)($query); + } + + /** + * @return Attempt + */ + public static function new(Url $dsn): Attempt + { + return PDO::of($dsn)->map( + static fn($implementation) => new self($implementation), + ); + } + + public static function logger(self $connection, LoggerInterface $logger): self + { + return new self(Logger::psr( + $connection->implementation, + $logger, + )); + } } diff --git a/src/Connection/Implementation.php b/src/Connection/Implementation.php new file mode 100644 index 0000000..d8bf06e --- /dev/null +++ b/src/Connection/Implementation.php @@ -0,0 +1,23 @@ + + */ + public function __invoke(Query|Query\Builder $query): Sequence; + public function driver(): Driver; +} diff --git a/src/Connection/Lazy.php b/src/Connection/Lazy.php deleted file mode 100644 index 16070e6..0000000 --- a/src/Connection/Lazy.php +++ /dev/null @@ -1,44 +0,0 @@ -load = $load; - } - - #[\Override] - public function __invoke(Query $query): Sequence - { - return ($this->connection())($query); - } - - /** - * @param callable(): Connection $load - */ - public static function of(callable $load): self - { - return new self($load); - } - - private function connection(): Connection - { - return $this->connection ?? $this->connection = ($this->load)(); - } -} diff --git a/src/Connection/Logger.php b/src/Connection/Logger.php index 6358087..459a7e4 100644 --- a/src/Connection/Logger.php +++ b/src/Connection/Logger.php @@ -4,37 +4,41 @@ namespace Formal\AccessLayer\Connection; use Formal\AccessLayer\{ - Connection, Query, Driver, }; use Innmind\Immutable\Sequence; use Psr\Log\LoggerInterface; -final class Logger implements Connection +/** + * @internal + */ +final class Logger implements Implementation { - private Connection $connection; + private Implementation $connection; private LoggerInterface $logger; - private function __construct(Connection $connection, LoggerInterface $logger) + private function __construct(Implementation $connection, LoggerInterface $logger) { $this->connection = $connection; $this->logger = $logger; } #[\Override] - public function __invoke(Query $query): Sequence + public function __invoke(Query|Query\Builder $query): Sequence { - // For the sake of simplicity the queries SQL is logged with the MySQL - // format. As otherwise it would require this decorator to retrieve the - // driver from the underlying connection. + if ($query instanceof Query\Builder) { + $normalized = $query->normalize($this->driver()); + } else { + $normalized = $query; + } try { $this->logger->debug( 'Query {sql} is about to be executed', [ - 'sql' => $query->sql(Driver::mysql), - 'parameters' => $query->parameters()->reduce( + 'sql' => $normalized->sql(), + 'parameters' => $normalized->parameters()->reduce( [], static fn(array $parameters, $parameter) => \array_merge( $parameters, @@ -52,7 +56,7 @@ public function __invoke(Query $query): Sequence $this->logger->error( 'Query {sql} failed with {kind}({message})', [ - 'sql' => $query->sql(Driver::mysql), + 'sql' => $normalized->sql(), 'kind' => \get_class($e), 'message' => $e->getMessage(), ], @@ -62,8 +66,14 @@ public function __invoke(Query $query): Sequence } } - public static function psr(Connection $connection, LoggerInterface $logger): self + public static function psr(Implementation $connection, LoggerInterface $logger): self { return new self($connection, $logger); } + + #[\Override] + public function driver(): Driver + { + return $this->connection->driver(); + } } diff --git a/src/Connection/PDO.php b/src/Connection/PDO.php index 281d248..ff1ad2b 100644 --- a/src/Connection/PDO.php +++ b/src/Connection/PDO.php @@ -4,7 +4,6 @@ namespace Formal\AccessLayer\Connection; use Formal\AccessLayer\{ - Connection, Query, Query\Parameter, Query\Parameter\Type, @@ -18,14 +17,20 @@ Authority\UserInformation\User, Authority\UserInformation\Password, }; -use Innmind\Immutable\Sequence; +use Innmind\Immutable\{ + Sequence, + Attempt, +}; -final class PDO implements Connection +/** + * @internal + */ +final class PDO implements Implementation { private \PDO $pdo; private Driver $driver; - private function __construct(Url $dsn, array $options = []) + private function __construct(Url $dsn) { $dsnUser = $dsn->authority()->userInformation()->user(); $dsnPassword = $dsn->authority()->userInformation()->password(); @@ -67,11 +72,11 @@ private function __construct(Url $dsn, array $options = []) $charset, ); - $this->pdo = new \PDO($pdoDsn, $user, $password, $options); + $this->pdo = new \PDO($pdoDsn, $user, $password); } #[\Override] - public function __invoke(Query $query): Sequence + public function __invoke(Query|Query\Builder $query): Sequence { return match (\get_class($query)) { Query\StartTransaction::class => $this->transaction( @@ -90,14 +95,20 @@ public function __invoke(Query $query): Sequence }; } - public static function of(Url $dsn): self + /** + * @return Attempt + */ + public static function of(Url $dsn): Attempt { - return new self($dsn); + return Attempt::defer( + static fn() => Attempt::of(static fn() => new self($dsn)), + ); } - public static function persistent(Url $dsn): self + #[\Override] + public function driver(): Driver { - return new self($dsn, [\PDO::ATTR_PERSISTENT => true]); + return $this->driver; } /** @@ -105,9 +116,13 @@ public static function persistent(Url $dsn): self * * @return Sequence */ - private function transaction(Query $query, callable $action): Sequence + private function transaction(Query\Builder $query, callable $action): Sequence { - $this->attempt($query, $action); + $this->attempt( + $query, + $query->normalize($this->driver), + $action, + ); /** @var Sequence */ return Sequence::of(); @@ -116,22 +131,30 @@ private function transaction(Query $query, callable $action): Sequence /** * @return Sequence */ - private function execute(Query $query): Sequence + private function execute(Query|Query\Builder $query): Sequence { - return match ($query->lazy()) { - true => $this->lazy($query), - false => $this->defer($query), + if ($query instanceof Query\Builder) { + $normalized = $query->normalize($this->driver); + } else { + $normalized = $query; + } + + return match ($normalized->lazy()) { + true => $this->lazy($query, $normalized), + false => $this->defer($query, $normalized), }; } /** * @return Sequence */ - private function lazy(Query $query): Sequence - { + private function lazy( + Query|Query\Builder $query, + Query $normalized, + ): Sequence { /** @var Sequence */ - return Sequence::lazy(function() use ($query): \Generator { - $statement = $this->prepare($query); + return Sequence::lazy(function() use ($query, $normalized): \Generator { + $statement = $this->prepare($query, $normalized); /** @psalm-suppress MixedAssignment */ while ($row = $statement->fetch(\PDO::FETCH_ASSOC)) { @@ -146,9 +169,11 @@ private function lazy(Query $query): Sequence /** * @return Sequence */ - private function defer(Query $query): Sequence - { - $statement = $this->prepare($query); + private function defer( + Query|Query\Builder $query, + Query $normalized, + ): Sequence { + $statement = $this->prepare($query, $normalized); /** @var Sequence */ return Sequence::defer( @@ -167,19 +192,23 @@ private function defer(Query $query): Sequence /** * @throws QueryFailed */ - private function prepare(Query $query): \PDOStatement - { + private function prepare( + Query|Query\Builder $query, + Query $normalized, + ): \PDOStatement { $statement = $this->guard( $query, - fn() => $this->pdo->prepare($query->sql($this->driver)), + $normalized, + fn() => $this->pdo->prepare($normalized->sql()), ); - $_ = $query->parameters()->reduce( + $_ = $normalized->parameters()->reduce( 0, - function(int $index, Parameter $parameter) use ($query, $statement): int { + function(int $index, Parameter $parameter) use ($query, $normalized, $statement): int { ++$index; $this->attempt( $query, + $normalized, fn(): bool => $statement->bindValue( $parameter->name()->match( static fn($name) => $name, @@ -194,7 +223,11 @@ function(int $index, Parameter $parameter) use ($query, $statement): int { }, ); - $this->attempt($query, static fn(): bool => $statement->execute()); + $this->attempt( + $query, + $normalized, + static fn(): bool => $statement->execute(), + ); return $statement; } @@ -204,8 +237,11 @@ function(int $index, Parameter $parameter) use ($query, $statement): int { * * @throws QueryFailed */ - private function guard(Query $query, callable $try): \PDOStatement - { + private function guard( + Query|Query\Builder $query, + Query $normalized, + callable $try, + ): \PDOStatement { try { $statement = $try(); @@ -225,8 +261,8 @@ private function guard(Query $query, callable $try): \PDOStatement } throw new QueryFailed( - $this->driver, $query, + $normalized, $errorInfo[0], $errorInfo[1], $errorInfo[2], @@ -239,8 +275,11 @@ private function guard(Query $query, callable $try): \PDOStatement * * @throws QueryFailed */ - private function attempt(Query $query, callable $attempt): void - { + private function attempt( + Query|Query\Builder $query, + Query $normalized, + callable $attempt, + ): void { try { if ($attempt()) { return; @@ -255,8 +294,8 @@ private function attempt(Query $query, callable $attempt): void } throw new QueryFailed( - $this->driver, $query, + $normalized, $errorInfo[0], $errorInfo[1], $errorInfo[2], diff --git a/src/Exception/QueryFailed.php b/src/Exception/QueryFailed.php index 0a0e72f..cce24a0 100644 --- a/src/Exception/QueryFailed.php +++ b/src/Exception/QueryFailed.php @@ -3,21 +3,18 @@ namespace Formal\AccessLayer\Exception; -use Formal\AccessLayer\{ - Query, - Driver, -}; +use Formal\AccessLayer\Query; final class QueryFailed extends RuntimeException { - private Query $query; + private Query|Query\Builder $query; private string $sqlstate; private ?int $driverSpecificCode; private ?string $driverSpecificMessage; public function __construct( - Driver $driver, - Query $query, + Query|Query\Builder $query, + Query $normalized, string $sqlstate, ?int $code, ?string $message, @@ -29,14 +26,14 @@ public function __construct( $this->driverSpecificMessage = $message; parent::__construct(\sprintf( "Query '%s' failed with: [%s] [%s] %s", - $query->sql($driver), + $normalized->sql(), $sqlstate, (string) $code, (string) $message, ), 0, $previous); } - public function query(): Query + public function query(): Query|Query\Builder { return $this->query; } diff --git a/src/Query.php b/src/Query.php index b5f5d3d..3e88ba5 100644 --- a/src/Query.php +++ b/src/Query.php @@ -9,16 +9,74 @@ /** * @psalm-immutable */ -interface Query +final class Query { + /** @var non-empty-string */ + private string $sql; + private bool $lazy; + /** @var Sequence */ + private Sequence $parameters; + + /** + * @param non-empty-string $sql + * @param Sequence $parameters + */ + private function __construct(string $sql, bool $lazy, Sequence $parameters) + { + $this->sql = $sql; + $this->lazy = $lazy; + $this->parameters = $parameters; + } + + /** + * @psalm-pure + * + * @param non-empty-string $sql + * @param Sequence $parameters + */ + public static function of(string $sql, ?Sequence $parameters = null): self + { + return new self($sql, false, $parameters ?? Sequence::of()); + } + + /** + * @psalm-pure + * + * @param non-empty-string $sql + * @param Sequence $parameters + */ + public static function lazily(string $sql, ?Sequence $parameters = null): self + { + return new self($sql, true, $parameters ?? Sequence::of()); + } + + public function with(Parameter $parameter): self + { + return new self( + $this->sql, + $this->lazy, + ($this->parameters)($parameter), + ); + } + /** * @return Sequence */ - public function parameters(): Sequence; + public function parameters(): Sequence + { + return $this->parameters; + } /** * @return non-empty-string */ - public function sql(Driver $driver): string; - public function lazy(): bool; + public function sql(): string + { + return $this->sql; + } + + public function lazy(): bool + { + return $this->lazy; + } } diff --git a/src/Query/Builder.php b/src/Query/Builder.php new file mode 100644 index 0000000..7528176 --- /dev/null +++ b/src/Query/Builder.php @@ -0,0 +1,17 @@ + */ - return Sequence::of(); - } - - #[\Override] - public function sql(Driver $driver): string - { - return 'COMMIT'; - } - - #[\Override] - public function lazy(): bool - { - return false; + return Query::of('COMMIT'); } } diff --git a/src/Query/CreateTable.php b/src/Query/CreateTable.php index 77a7599..283868d 100644 --- a/src/Query/CreateTable.php +++ b/src/Query/CreateTable.php @@ -20,7 +20,7 @@ /** * @psalm-immutable */ -final class CreateTable implements Query +final class CreateTable implements Builder { private Name $name; /** @var Sequence */ @@ -102,17 +102,9 @@ public function constraint(PrimaryKey|ForeignKey|Unique $constraint): self } #[\Override] - public function parameters(): Sequence + public function normalize(Driver $driver): Query { - /** @var Sequence */ - return Sequence::of(); - } - - #[\Override] - public function sql(Driver $driver): string - { - /** @var non-empty-string */ - return \sprintf( + return Query::of(\sprintf( 'CREATE TABLE %s %s (%s%s)', $this->ifNotExists ? 'IF NOT EXISTS' : '', $this->name->sql($driver), @@ -129,12 +121,6 @@ public function sql(Driver $driver): string ->toString(), static fn() => '', ), - ); - } - - #[\Override] - public function lazy(): bool - { - return false; + )); } } diff --git a/src/Query/Delete.php b/src/Query/Delete.php index d871d47..a4af30c 100644 --- a/src/Query/Delete.php +++ b/src/Query/Delete.php @@ -19,7 +19,7 @@ /** * @psalm-immutable */ -final class Delete implements Query +final class Delete implements Builder { private Name|Name\Aliased $table; /** @var Sequence */ @@ -66,30 +66,23 @@ public function where(Specification $specification): self } #[\Override] - public function parameters(): Sequence + public function normalize(Driver $driver): Query { - return $this->where->parameters(); - } - - #[\Override] - public function sql(Driver $driver): string - { - return match ($driver) { - Driver::mysql => $this->mysqlSql($driver), - Driver::postgres => $this->postgresSql($driver), - }; - } + [$where, $parameters] = $this->where->normalize($driver); - #[\Override] - public function lazy(): bool - { - return false; + return Query::of( + match ($driver) { + Driver::mysql => $this->mysqlSql($driver, $where), + Driver::postgres => $this->postgresSql($driver, $where), + }, + $parameters, + ); } /** * @return non-empty-string */ - private function mysqlSql(Driver $driver): string + private function mysqlSql(Driver $driver, string $where): string { /** @var non-empty-string */ return \sprintf( @@ -105,17 +98,16 @@ private function mysqlSql(Driver $driver): string ->map(Str::of(...)) ->fold(new Concat) ->toString(), - $this->where->sql($driver), + $where, ); } /** * @return non-empty-string */ - private function postgresSql(Driver $driver): string + private function postgresSql(Driver $driver, string $where): string { $joins = ''; - $where = $this->where->sql($driver); if (!$this->joins->empty()) { $joins = Str::of(', ') diff --git a/src/Query/DropTable.php b/src/Query/DropTable.php index e062ac5..484d37f 100644 --- a/src/Query/DropTable.php +++ b/src/Query/DropTable.php @@ -8,12 +8,11 @@ Table\Name, Driver, }; -use Innmind\Immutable\Sequence; /** * @psalm-immutable */ -final class DropTable implements Query +final class DropTable implements Builder { private Name $name; private bool $ifExists; @@ -41,26 +40,12 @@ public static function ifExists(Name $name): self } #[\Override] - public function parameters(): Sequence + public function normalize(Driver $driver): Query { - /** @var Sequence */ - return Sequence::of(); - } - - #[\Override] - public function sql(Driver $driver): string - { - /** @var non-empty-string */ - return \sprintf( + return Query::of(\sprintf( 'DROP TABLE %s %s', $this->ifExists ? 'IF EXISTS' : '', $this->name->sql($driver), - ); - } - - #[\Override] - public function lazy(): bool - { - return false; + )); } } diff --git a/src/Query/Insert.php b/src/Query/Insert.php index f7a4d68..412b640 100644 --- a/src/Query/Insert.php +++ b/src/Query/Insert.php @@ -17,7 +17,7 @@ /** * @psalm-immutable */ -final class Insert implements Query +final class Insert implements Builder { private function __construct( private Name $table, @@ -34,36 +34,11 @@ public static function into(Name $table, Row|Select $row): self } #[\Override] - public function parameters(): Sequence - { - if ($this->row instanceof Select) { - return $this->row->parameters(); - } - - return $this->row->values()->map( - static fn($value) => Parameter::of($value->value(), $value->type()), - ); - } - - #[\Override] - public function sql(Driver $driver): string - { - return $this->buildInsert($driver); - } - - #[\Override] - public function lazy(): bool - { - return false; - } - - /** - * @return non-empty-string - */ - private function buildInsert(Driver $driver): string + public function normalize(Driver $driver): Query { if ($this->row instanceof Select) { $columns = $this->row->names(); + $query = $this->row->normalize($driver); if ($columns->empty()) { throw new \LogicException('You need to specify the columns to select when inserting'); @@ -71,11 +46,14 @@ private function buildInsert(Driver $driver): string $keys = $columns->map(static fn($column) => $column->sql($driver)); - return \sprintf( - 'INSERT INTO %s (%s) %s', - $this->table->sql($driver), - Str::of(', ')->join($keys)->toString(), - $this->row->sql($driver), + return Query::of( + \sprintf( + 'INSERT INTO %s (%s) %s', + $this->table->sql($driver), + Str::of(', ')->join($keys)->toString(), + $query->sql(), + ), + $query->parameters(), ); } @@ -84,11 +62,19 @@ private function buildInsert(Driver $driver): string /** @var Sequence */ $values = $this->row->values()->map(static fn() => '?'); - return \sprintf( - 'INSERT INTO %s (%s) VALUES (%s)', - $this->table->sql($driver), - Str::of(', ')->join($keys)->toString(), - Str::of(', ')->join($values)->toString(), + return Query::of( + \sprintf( + 'INSERT INTO %s (%s) VALUES (%s)', + $this->table->sql($driver), + Str::of(', ')->join($keys)->toString(), + Str::of(', ')->join($values)->toString(), + ), + $this->row->values()->map( + static fn($value) => Parameter::of( + $value->value(), + $value->type(), + ), + ), ); } } diff --git a/src/Query/MultipleInsert.php b/src/Query/MultipleInsert.php index 1149283..d2a7f2a 100644 --- a/src/Query/MultipleInsert.php +++ b/src/Query/MultipleInsert.php @@ -18,7 +18,7 @@ /** * @psalm-immutable */ -final class MultipleInsert implements Query +final class MultipleInsert implements Builder { private Name $table; /** @var Sequence */ @@ -62,23 +62,14 @@ public static function into( } #[\Override] - public function parameters(): Sequence + public function normalize(Driver $driver): Query { - return $this->rows->flatMap(static fn($row) => $row->values()->map( - static fn($value) => Parameter::of($value->value(), $value->type()), - )); - } - - #[\Override] - public function sql(Driver $driver): string - { - return $this->buildInsert($driver); - } - - #[\Override] - public function lazy(): bool - { - return false; + return Query::of( + $this->buildInsert($driver), + $this->rows->flatMap(static fn($row) => $row->values()->map( + static fn($value) => Parameter::of($value->value(), $value->type()), + )), + ); } /** diff --git a/src/Query/Rollback.php b/src/Query/Rollback.php index 1b22d9b..5f1d6dc 100644 --- a/src/Query/Rollback.php +++ b/src/Query/Rollback.php @@ -7,29 +7,15 @@ Query, Driver, }; -use Innmind\Immutable\Sequence; /** * @psalm-immutable */ -final class Rollback implements Query +final class Rollback implements Builder { #[\Override] - public function parameters(): Sequence + public function normalize(Driver $driver): Query { - /** @var Sequence */ - return Sequence::of(); - } - - #[\Override] - public function sql(Driver $driver): string - { - return 'ROLLBACK'; - } - - #[\Override] - public function lazy(): bool - { - return false; + return Query::of('ROLLBACK'); } } diff --git a/src/Query/SQL.php b/src/Query/SQL.php index 1de2c6b..b414361 100644 --- a/src/Query/SQL.php +++ b/src/Query/SQL.php @@ -3,78 +3,35 @@ namespace Formal\AccessLayer\Query; -use Formal\AccessLayer\{ - Query, - Driver, -}; +use Formal\AccessLayer\Query; use Innmind\Immutable\Sequence; /** - * @psalm-immutable + * @deprecated Use Query instead */ -final class SQL implements Query +final class SQL { - /** @var non-empty-string */ - private string $sql; - private bool $lazy; - /** @var Sequence */ - private Sequence $parameters; - - /** - * @param non-empty-string $sql - * @param Sequence $parameters - */ - private function __construct(string $sql, bool $lazy, Sequence $parameters) - { - $this->sql = $sql; - $this->lazy = $lazy; - $this->parameters = $parameters; - } - /** * @psalm-pure + * @deprecated Use Query::of() instead * * @param non-empty-string $sql + * @param Sequence $parameters */ - public static function of(string $sql): self + public static function of(string $sql, ?Sequence $parameters = null): Query { - return new self($sql, false, Sequence::of()); + return Query::of($sql, $parameters); } /** * @psalm-pure + * @deprecated Use Query::lazily() instead * * @param non-empty-string $sql + * @param Sequence $parameters */ - public static function onDemand(string $sql): self - { - return new self($sql, true, Sequence::of()); - } - - public function with(Parameter $parameter): self - { - return new self( - $this->sql, - $this->lazy, - ($this->parameters)($parameter), - ); - } - - #[\Override] - public function parameters(): Sequence - { - return $this->parameters; - } - - #[\Override] - public function sql(Driver $driver): string - { - return $this->sql; - } - - #[\Override] - public function lazy(): bool + public static function onDemand(string $sql, ?Sequence $parameters = null): Query { - return $this->lazy; + return Query::lazily($sql, $parameters); } } diff --git a/src/Query/Select.php b/src/Query/Select.php index 1ed79b1..8c362e2 100644 --- a/src/Query/Select.php +++ b/src/Query/Select.php @@ -24,7 +24,7 @@ /** * @psalm-immutable */ -final class Select implements Query +final class Select implements Builder { /** * @param Sequence $joins @@ -70,8 +70,17 @@ public static function from(Name|Name\Aliased $table): self /** * @psalm-pure + * @deprecated Use ::lazily() instead */ public static function onDemand(Name|Name\Aliased $table): self + { + return self::lazily($table); + } + + /** + * @psalm-pure + */ + public static function lazily(Name|Name\Aliased $table): self { /** @var Maybe */ $count = Maybe::nothing(); @@ -197,23 +206,11 @@ public function limit(int $limit, ?int $offset = null): self } #[\Override] - public function parameters(): Sequence - { - return $this - ->columns - ->keep(Instance::of(Row\Value::class)) - ->map(static fn($value) => Parameter::of( - $value->value(), - $value->type(), - )) - ->append($this->where->parameters()); - } - - #[\Override] - public function sql(Driver $driver): string + public function normalize(Driver $driver): Query { + [$where, $parameters] = $this->where->normalize($driver); /** @var non-empty-string */ - return \sprintf( + $sql = \sprintf( 'SELECT %s FROM %s%s %s%s%s%s', $this ->count @@ -229,7 +226,7 @@ public function sql(Driver $driver): string ->map(Str::of(...)) ->fold(new Concat) ->toString(), - $this->where->sql($driver), + $where, match ($this->orderBy) { null => '', default => \sprintf( @@ -247,12 +244,19 @@ public function sql(Driver $driver): string default => ' OFFSET '.$this->offset, }, ); - } + $parameters = $this + ->columns + ->keep(Instance::of(Row\Value::class)) + ->map(static fn($value) => Parameter::of( + $value->value(), + $value->type(), + )) + ->append($parameters); - #[\Override] - public function lazy(): bool - { - return $this->lazy; + return match ($this->lazy) { + true => Query::lazily($sql, $parameters), + false => Query::of($sql, $parameters), + }; } /** diff --git a/src/Query/StartTransaction.php b/src/Query/StartTransaction.php index 5fd1248..06bda65 100644 --- a/src/Query/StartTransaction.php +++ b/src/Query/StartTransaction.php @@ -7,29 +7,15 @@ Query, Driver, }; -use Innmind\Immutable\Sequence; /** * @psalm-immutable */ -final class StartTransaction implements Query +final class StartTransaction implements Builder { #[\Override] - public function parameters(): Sequence + public function normalize(Driver $driver): Query { - /** @var Sequence */ - return Sequence::of(); - } - - #[\Override] - public function sql(Driver $driver): string - { - return 'START TRANSACTION'; - } - - #[\Override] - public function lazy(): bool - { - return false; + return Query::of('START TRANSACTION'); } } diff --git a/src/Query/Update.php b/src/Query/Update.php index 75c2043..ba635c5 100644 --- a/src/Query/Update.php +++ b/src/Query/Update.php @@ -18,7 +18,7 @@ /** * @psalm-immutable */ -final class Update implements Query +final class Update implements Builder { private Name|Name\Aliased $table; private Row $row; @@ -52,36 +52,28 @@ public function where(Specification $specification): self } #[\Override] - public function parameters(): Sequence - { - return $this - ->row - ->values() - ->map(static fn($value) => Parameter::of($value->value(), $value->type())) - ->append($this->where->parameters()); - } - - #[\Override] - public function sql(Driver $driver): string + public function normalize(Driver $driver): Query { + [$where, $parameters] = $this->where->normalize($driver); /** @var Sequence */ $columns = $this ->row ->values() ->map(static fn($value) => "{$value->columnSql($driver)} = ?"); + $parameters = $this + ->row + ->values() + ->map(static fn($value) => Parameter::of($value->value(), $value->type())) + ->append($parameters); - /** @var non-empty-string */ - return \sprintf( - 'UPDATE %s SET %s %s', - $this->table->sql($driver), - Str::of(', ')->join($columns)->toString(), - $this->where->sql($driver), + return Query::of( + \sprintf( + 'UPDATE %s SET %s %s', + $this->table->sql($driver), + Str::of(', ')->join($columns)->toString(), + $where, + ), + $parameters, ); } - - #[\Override] - public function lazy(): bool - { - return false; - } } diff --git a/src/Query/Where.php b/src/Query/Where.php index 06712e8..47ad4bc 100644 --- a/src/Query/Where.php +++ b/src/Query/Where.php @@ -53,33 +53,26 @@ public static function everything(): self } /** - * @return Sequence + * @return array{string, Sequence} */ - public function parameters(): Sequence - { - /** @var Sequence */ - $parameters = Sequence::of(); - - if (\is_null($this->specification)) { - return $parameters; - } - - return $this->findParamaters( - $parameters, - $this->specification, - ); - } - - public function sql(Driver $driver): string + public function normalize(Driver $driver): array { if (\is_null($this->specification)) { - return ''; + return ['', Sequence::of()]; } - return \sprintf( - 'WHERE %s', - $this->buildSql($driver, $this->specification), - ); + // todo optimize this process to avoid traversing everything twice + return [ + \sprintf( + 'WHERE %s', + $this->buildSql($driver, $this->specification), + ), + $this->findParamaters( + $driver, + Sequence::of(), + $this->specification, + ), + ]; } private function buildSql( @@ -203,7 +196,15 @@ private function buildInSql( return \sprintf( '%s IN (%s)', $this->buildColumn($driver, $specification), - $specification->value()->sql($driver), + $specification->value()->sql(), + ); + } + + if ($specification->value() instanceof Builder) { + return \sprintf( + '%s IN (%s)', + $this->buildColumn($driver, $specification), + $specification->value()->normalize($driver)->sql(), ); } @@ -227,6 +228,7 @@ private function buildInSql( * @return Sequence */ private function findParamaters( + Driver $driver, Sequence $parameters, Specification $specification, ): Sequence { @@ -241,6 +243,7 @@ private function findParamaters( $specification->left()->value() === $specification->right()->value() ) { return $this->findComparatorParameters( + $driver, $parameters, $specification->left(), ); @@ -257,6 +260,7 @@ private function findParamaters( $specification->left()->value() === $specification->right()->value() ) { return $this->findComparatorParameters( + $driver, $parameters, $specification->left(), ); @@ -264,17 +268,21 @@ private function findParamaters( return match (true) { $specification instanceof Not => $this->findParamaters( + $driver, $parameters, $specification->specification(), ), $specification instanceof Composite => $this->findParamaters( + $driver, $parameters, $specification->left(), )->append($this->findParamaters( + $driver, $parameters, $specification->right(), )), $specification instanceof Comparator => $this->findComparatorParameters( + $driver, $parameters, $specification, ), @@ -287,6 +295,7 @@ private function findParamaters( * @return Sequence */ private function findComparatorParameters( + Driver $driver, Sequence $parameters, Comparator $specification, ): Sequence { @@ -306,6 +315,15 @@ private function findComparatorParameters( return $parameters->append($specification->value()->parameters()); } + if ($specification->value() instanceof Builder) { + return $parameters->append( + $specification + ->value() + ->normalize($driver) + ->parameters(), + ); + } + /** * @var mixed $in */