Skip to content

Commit

Permalink
Support Literal values in inserts
Browse files Browse the repository at this point in the history
  • Loading branch information
MasterOdin committed Aug 4, 2024
1 parent eae55bc commit b0afe3a
Show file tree
Hide file tree
Showing 5 changed files with 300 additions and 7 deletions.
37 changes: 30 additions & 7 deletions src/Phinx/Db/Adapter/PdoAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -336,9 +336,22 @@ public function insert(Table $table, array $row): void
$sql .= '(' . implode(', ', array_map([$this, 'quoteValue'], $row)) . ');';
$this->output->writeln($sql);
} else {
$sql .= '(' . implode(', ', array_fill(0, count($columns), '?')) . ')';
$sql .= '(';
$vals = [];
$values = [];
foreach ($row as $value) {
$values[] = $value instanceof Literal ? (string)$value : '?';
if (!($value instanceof Literal)) {
if (is_bool($value)) {
$vals[] = $this->castToBool($value);
} else {
$vals[] = $value;
}
}
}
$sql .= implode(', ', $values) . ')';
$stmt = $this->getConnection()->prepare($sql);
$stmt->execute(array_values($row));
$stmt->execute($vals);
}
}

Expand All @@ -358,6 +371,10 @@ protected function quoteValue(mixed $value): mixed
return 'null';
}

if ($value instanceof Literal) {
return (string)$value;
}

return $this->getConnection()->quote($value);
}

Expand Down Expand Up @@ -392,17 +409,23 @@ public function bulkinsert(Table $table, array $rows): void
$sql .= implode(', ', $values) . ';';
$this->output->writeln($sql);
} else {
$count_keys = count($keys);
$query = '(' . implode(', ', array_fill(0, $count_keys, '?')) . ')';
$count_vars = count($rows);
$queries = array_fill(0, $count_vars, $query);
$queries = [];
foreach ($rows as $row) {
$values = [];
foreach ($row as $value) {
$values[] = $value instanceof Literal ? (string)$value : '?';
}
$queries[] = '(' . implode(', ', $values) . ')';
}
$sql .= implode(',', $queries);
$stmt = $this->getConnection()->prepare($sql);
$vals = [];

foreach ($rows as $row) {
foreach ($row as $v) {
if (is_bool($v)) {
if ($v instanceof Literal) {
continue;
} elseif (is_bool($v)) {
$vals[] = $this->castToBool($v);
} else {
$vals[] = $v;
Expand Down
69 changes: 69 additions & 0 deletions tests/Phinx/Db/Adapter/MysqlAdapterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2180,9 +2180,41 @@ public function testBulkInsertData()
$this->assertEquals(2, $rows[1]['column2']);
$this->assertEquals(3, $rows[2]['column2']);
$this->assertEquals('test', $rows[0]['column3']);
$this->assertEquals('test', $rows[1]['column3']);
$this->assertEquals('test', $rows[2]['column3']);
}

public function testBulkInsertLiteral()
{
$data = [
[
'column1' => 'value1',
'column2' => Literal::from('CURRENT_TIMESTAMP'),
],
[
'column1' => 'value2',
'column2' => '2024-01-01 00:00:00',
],
[
'column1' => 'value3',
'column2' => '2025-01-01 00:00:00',
],
];
$table = new Table('table1', [], $this->adapter);
$table->addColumn('column1', 'string')
->addColumn('column2', 'datetime')
->insert($data)
->save();

$rows = $this->adapter->fetchAll('SELECT * FROM table1');
$this->assertEquals('value1', $rows[0]['column1']);
$this->assertEquals('value2', $rows[1]['column1']);
$this->assertEquals('value3', $rows[2]['column1']);
$this->assertMatchesRegularExpression('/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/', $rows[0]['column2']);
$this->assertEquals('2024-01-01 00:00:00', $rows[1]['column2']);
$this->assertEquals('2025-01-01 00:00:00', $rows[2]['column2']);
}

public function testInsertData()
{
$data = [
Expand Down Expand Up @@ -2215,9 +2247,46 @@ public function testInsertData()
$this->assertEquals(2, $rows[1]['column2']);
$this->assertEquals(3, $rows[2]['column2']);
$this->assertEquals('test', $rows[0]['column3']);
$this->assertEquals('test', $rows[1]['column3']);
$this->assertEquals('foo', $rows[2]['column3']);
}

public function testInsertLiteral()
{
$data = [
[
'column1' => 'value1',
'column3' => Literal::from('CURRENT_TIMESTAMP'),
],
[
'column1' => 'value2',
'column3' => '2024-01-01 00:00:00',
],
[
'column1' => 'value3',
'column2' => 'foo',
'column3' => '2025-01-01 00:00:00',
],
];
$table = new Table('table1', [], $this->adapter);
$table->addColumn('column1', 'string')
->addColumn('column2', 'string', ['default' => 'test'])
->addColumn('column3', 'datetime')
->insert($data)
->save();

$rows = $this->adapter->fetchAll('SELECT * FROM table1');
$this->assertEquals('value1', $rows[0]['column1']);
$this->assertEquals('value2', $rows[1]['column1']);
$this->assertEquals('value3', $rows[2]['column1']);
$this->assertEquals('test', $rows[0]['column2']);
$this->assertEquals('test', $rows[1]['column2']);
$this->assertEquals('foo', $rows[2]['column2']);
$this->assertMatchesRegularExpression('/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/', $rows[0]['column3']);
$this->assertEquals('2024-01-01 00:00:00', $rows[1]['column3']);
$this->assertEquals('2025-01-01 00:00:00', $rows[2]['column3']);
}

public function testDumpCreateTable()
{
$inputDefinition = new InputDefinition([new InputOption('dry-run')]);
Expand Down
67 changes: 67 additions & 0 deletions tests/Phinx/Db/Adapter/PostgresAdapterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2369,6 +2369,37 @@ public function testBulkInsertBoolean()
$this->assertNull($rows[2]['column1']);
}

public function testBulkInsertLiteral()
{
$data = [
[
'column1' => 'value1',
'column2' => Literal::from('CURRENT_TIMESTAMP'),
],
[
'column1' => 'value2',
'column2' => '2024-01-01 00:00:00',
],
[
'column1' => 'value3',
'column2' => '2025-01-01 00:00:00',
],
];
$table = new Table('table1', [], $this->adapter);
$table->addColumn('column1', 'string')
->addColumn('column2', 'datetime')
->insert($data)
->save();

$rows = $this->adapter->fetchAll('SELECT * FROM table1');
$this->assertEquals('value1', $rows[0]['column1']);
$this->assertEquals('value2', $rows[1]['column1']);
$this->assertEquals('value3', $rows[2]['column1']);
$this->assertMatchesRegularExpression('/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/', $rows[0]['column2']);
$this->assertEquals('2024-01-01 00:00:00', $rows[1]['column2']);
$this->assertEquals('2025-01-01 00:00:00', $rows[2]['column2']);
}

public function testInsertData()
{
$table = new Table('table1', [], $this->adapter);
Expand Down Expand Up @@ -2418,6 +2449,42 @@ public function testInsertBoolean()
$this->assertNull($rows[2]['column1']);
}

public function testInsertLiteral()
{
$data = [
[
'column1' => 'value1',
'column3' => Literal::from('CURRENT_TIMESTAMP'),
],
[
'column1' => 'value2',
'column3' => '2024-01-01 00:00:00',
],
[
'column1' => 'value3',
'column2' => 'foo',
'column3' => '2025-01-01 00:00:00',
],
];
$table = new Table('table1', [], $this->adapter);
$table->addColumn('column1', 'string')
->addColumn('column2', 'string', ['default' => 'test'])
->addColumn('column3', 'datetime')
->insert($data)
->save();

$rows = $this->adapter->fetchAll('SELECT * FROM table1');
$this->assertEquals('value1', $rows[0]['column1']);
$this->assertEquals('value2', $rows[1]['column1']);
$this->assertEquals('value3', $rows[2]['column1']);
$this->assertEquals('test', $rows[0]['column2']);
$this->assertEquals('test', $rows[1]['column2']);
$this->assertEquals('foo', $rows[2]['column2']);
$this->assertMatchesRegularExpression('/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/', $rows[0]['column3']);
$this->assertEquals('2024-01-01 00:00:00', $rows[1]['column3']);
$this->assertEquals('2025-01-01 00:00:00', $rows[2]['column3']);
}

public function testInsertDataWithSchema()
{
$this->adapter->createSchema('schema1');
Expand Down
67 changes: 67 additions & 0 deletions tests/Phinx/Db/Adapter/SQLiteAdapterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1775,6 +1775,37 @@ public function testBulkInsertData()
$this->assertNull($rows[3]['column2']);
}

public function testBulkInsertLiteral()
{
$data = [
[
'column1' => 'value1',
'column2' => Literal::from('CURRENT_TIMESTAMP'),
],
[
'column1' => 'value2',
'column2' => '2024-01-01 00:00:00',
],
[
'column1' => 'value3',
'column2' => '2025-01-01 00:00:00',
],
];
$table = new Table('table1', [], $this->adapter);
$table->addColumn('column1', 'string')
->addColumn('column2', 'datetime')
->insert($data)
->save();

$rows = $this->adapter->fetchAll('SELECT * FROM table1');
$this->assertEquals('value1', $rows[0]['column1']);
$this->assertEquals('value2', $rows[1]['column1']);
$this->assertEquals('value3', $rows[2]['column1']);
$this->assertMatchesRegularExpression('/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/', $rows[0]['column2']);
$this->assertEquals('2024-01-01 00:00:00', $rows[1]['column2']);
$this->assertEquals('2025-01-01 00:00:00', $rows[2]['column2']);
}

public function testInsertData()
{
$table = new Table('table1', [], $this->adapter);
Expand Down Expand Up @@ -1816,6 +1847,42 @@ public function testInsertData()
$this->assertNull($rows[3]['column2']);
}

public function testInsertLiteral()
{
$data = [
[
'column1' => 'value1',
'column3' => Literal::from('CURRENT_TIMESTAMP'),
],
[
'column1' => 'value2',
'column3' => '2024-01-01 00:00:00',
],
[
'column1' => 'value3',
'column2' => 'foo',
'column3' => '2025-01-01 00:00:00',
],
];
$table = new Table('table1', [], $this->adapter);
$table->addColumn('column1', 'string')
->addColumn('column2', 'string', ['default' => 'test'])
->addColumn('column3', 'datetime')
->insert($data)
->save();

$rows = $this->adapter->fetchAll('SELECT * FROM table1');
$this->assertEquals('value1', $rows[0]['column1']);
$this->assertEquals('value2', $rows[1]['column1']);
$this->assertEquals('value3', $rows[2]['column1']);
$this->assertEquals('test', $rows[0]['column2']);
$this->assertEquals('test', $rows[1]['column2']);
$this->assertEquals('foo', $rows[2]['column2']);
$this->assertMatchesRegularExpression('/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/', $rows[0]['column3']);
$this->assertEquals('2024-01-01 00:00:00', $rows[1]['column3']);
$this->assertEquals('2025-01-01 00:00:00', $rows[2]['column3']);
}

public function testBulkInsertDataEnum()
{
$table = new Table('table1', [], $this->adapter);
Expand Down
67 changes: 67 additions & 0 deletions tests/Phinx/Db/Adapter/SqlServerAdapterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1307,6 +1307,37 @@ public function testBulkInsertData()
$this->assertEquals(3, $rows[2]['column2']);
}

public function testBulkInsertLiteral()
{
$data = [
[
'column1' => 'value1',
'column2' => Literal::from('CURRENT_TIMESTAMP'),
],
[
'column1' => 'value2',
'column2' => '2024-01-01 00:00:00',
],
[
'column1' => 'value3',
'column2' => '2025-01-01 00:00:00',
],
];
$table = new Table('table1', [], $this->adapter);
$table->addColumn('column1', 'string')
->addColumn('column2', 'datetime')
->insert($data)
->save();

$rows = $this->adapter->fetchAll('SELECT * FROM table1');
$this->assertEquals('value1', $rows[0]['column1']);
$this->assertEquals('value2', $rows[1]['column1']);
$this->assertEquals('value3', $rows[2]['column1']);
$this->assertMatchesRegularExpression('/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/', $rows[0]['column2']);
$this->assertEquals('2024-01-01 00:00:00', $rows[1]['column2']);
$this->assertEquals('2025-01-01 00:00:00', $rows[2]['column2']);
}

public function testInsertData()
{
$table = new Table('table1', [], $this->adapter);
Expand Down Expand Up @@ -1340,6 +1371,42 @@ public function testInsertData()
$this->assertEquals(3, $rows[2]['column2']);
}

public function testInsertLiteral()
{
$data = [
[
'column1' => 'value1',
'column3' => Literal::from('CURRENT_TIMESTAMP'),
],
[
'column1' => 'value2',
'column3' => '2024-01-01 00:00:00',
],
[
'column1' => 'value3',
'column2' => 'foo',
'column3' => '2025-01-01 00:00:00',
],
];
$table = new Table('table1', [], $this->adapter);
$table->addColumn('column1', 'string')
->addColumn('column2', 'string', ['default' => 'test'])
->addColumn('column3', 'datetime')
->insert($data)
->save();

$rows = $this->adapter->fetchAll('SELECT * FROM table1');
$this->assertEquals('value1', $rows[0]['column1']);
$this->assertEquals('value2', $rows[1]['column1']);
$this->assertEquals('value3', $rows[2]['column1']);
$this->assertEquals('test', $rows[0]['column2']);
$this->assertEquals('test', $rows[1]['column2']);
$this->assertEquals('foo', $rows[2]['column2']);
$this->assertMatchesRegularExpression('/[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}/', $rows[0]['column3']);
$this->assertEquals('2024-01-01 00:00:00', $rows[1]['column3']);
$this->assertEquals('2025-01-01 00:00:00', $rows[2]['column3']);
}

public function testTruncateTable()
{
$table = new Table('table1', [], $this->adapter);
Expand Down

0 comments on commit b0afe3a

Please sign in to comment.