From 21eb9628c5371747f0e086bfe8009f4024a252e9 Mon Sep 17 00:00:00 2001 From: Jan Iwanow Date: Mon, 8 Apr 2019 08:25:32 +1100 Subject: [PATCH] Wrote the code --- src/Query.php | 35 ++++++++++++++++++ src/functions.php | 77 +++++++++++++++++++++++++++++++++++++++ tests/FunctionsTest.php | 79 +++++++++++++++++++++++++++++++++++++++++ tests/QueryTest.php | 46 ++++++++++++++++++++++++ 4 files changed, 237 insertions(+) create mode 100644 src/Query.php create mode 100644 src/functions.php create mode 100644 tests/FunctionsTest.php create mode 100644 tests/QueryTest.php diff --git a/src/Query.php b/src/Query.php new file mode 100644 index 0000000..ad16a93 --- /dev/null +++ b/src/Query.php @@ -0,0 +1,35 @@ +connection = $connection; + } + + public function execute(string $table, array $dataset, array $types = []): int + { + if (empty($dataset)) { + return 0; + } + + $sql = sql($this->connection->getDatabasePlatform(), new Identifier($table), $dataset); + + return $this->connection->executeUpdate($sql, parameters($dataset), types($types, count($dataset))); + } + + public function transactional(string $table, array $dataset, array $types = []): int + { + return $this->connection->transactional(static function () use ($table, $dataset, $types): int { + return $this->execute($table, $dataset, $types); + }); + } +} diff --git a/src/functions.php b/src/functions.php new file mode 100644 index 0000000..da07e40 --- /dev/null +++ b/src/functions.php @@ -0,0 +1,77 @@ +getQuotedName($platform), + stringify_columns($columns), + generate_placeholders(count($columns), count($dataset)) + ); + + return $sql; +} + +function extract_columns(array $dataset): array +{ + if (empty($dataset)) { + return []; + } + + $first = reset($dataset); + + return array_keys($first); +} + +function quote_columns(AbstractPlatform $platform, array $columns): array +{ + return array_map(static function (string $column) use ($platform): string { + return (new Identifier($column))->getQuotedName($platform); + }, $columns); +} + +function stringify_columns(array $columns): string +{ + return empty($columns) ? '' : sprintf('(%s)', implode(', ', $columns)); +} + +function generate_placeholders(int $columnsLength, int $datasetLength): string +{ + // (?, ?, ?, ?) + $placeholders = sprintf('(%s)', implode(', ', array_fill(0, $columnsLength, '?'))); + + // (?, ?), (?, ?) + return implode(', ', array_fill(0, $datasetLength, $placeholders)); +} + +function parameters(array $dataset): array +{ + return array_reduce($dataset, static function (array $flattenedValues, array $dataset): array { + return array_merge($flattenedValues, array_values($dataset)); + }, []); +} + +function types(array $types, int $datasetLength): array +{ + if (empty($types)) { + return []; + } + + $types = array_values($types); + + $positionalTypes = []; + + for ($idx = 1; $idx <= $datasetLength; $idx++) { + $positionalTypes = array_merge($positionalTypes, $types); + } + + return $positionalTypes; +} diff --git a/tests/FunctionsTest.php b/tests/FunctionsTest.php new file mode 100644 index 0000000..a23c2d9 --- /dev/null +++ b/tests/FunctionsTest.php @@ -0,0 +1,79 @@ + 111, + 'bar' => 222, + 'qux' => 333 + ], + [ + 'foo' => 444, + 'bar' => 555, + 'qux' => 777 + ], + ]; + + public function testExtractColumns(): void + { + static::assertEquals(['foo', 'bar', 'qux'], extract_columns(static::DATASET)); + static::assertEquals([], extract_columns([])); + } + + public function testStringifyColumns(): void + { + static::assertEquals('(foo, bar, qux)', stringify_columns(['foo', 'bar', 'qux'])); + static::assertEquals('', stringify_columns([])); + } + + public function testPlaceholders(): void + { + static::assertEquals( + '(?, ?, ?, ?, ?), (?, ?, ?, ?, ?)', + generate_placeholders(5, 2) + ); + } + + public function testParameters(): void + { + static::assertEquals([111, 222, 333, 444, 555, 777], parameters(static::DATASET)); + static::assertEquals([], parameters([])); + } + + public function testTypes(): void + { + $types = ['string', 'text', 'json']; + + $expected = [ + 'string', 'text', 'json', + 'string', 'text', 'json' + ]; + + static::assertEquals($expected, types($types, 2)); + } + + public function testSql(): void + { + $sql = sql(new PostgreSqlPlatform(), new Identifier('foo'), static::DATASET); + $expected = 'INSERT INTO foo (foo, bar, qux) VALUES (?, ?, ?), (?, ?, ?);'; + + static::assertEquals($expected, $sql); + } +} diff --git a/tests/QueryTest.php b/tests/QueryTest.php new file mode 100644 index 0000000..5a30fb2 --- /dev/null +++ b/tests/QueryTest.php @@ -0,0 +1,46 @@ +shouldReceive('getDatabasePlatform') + ->once() + ->andReturn(new PostgreSqlPlatform()); + + $connection->shouldReceive('executeUpdate') + ->once() + ->with('INSERT INTO foo (foo, bar) VALUES (?, ?), (?, ?);', [111, 222, 333, 444], []) + ->andReturn(2); + + $rows = (new Query($connection))->execute('foo', [ + ['foo' => 111, 'bar' => 222], + ['foo' => 333, 'bar' => 444], + ]); + + static::assertEquals(2, $rows); + } + + public function testExecuteWithEmptyDataset(): void + { + $connection = Mockery::mock(Connection::class); + $connection->shouldNotReceive('getDatabasePlatform', 'executeUpdate'); + + $rows = (new Query($connection))->execute('foo', []); + + static::assertEquals(0, $rows); + } +}