Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

POC: added XML support. #14

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Builder/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class Builder
use Concerns\HasLines;
use Concerns\IgnoresLines;
use Concerns\SetsValues;
use Concerns\HasXmlRows;

private DatabaseManager $databaseManager;
private Grammar $grammar;
Expand Down
7 changes: 7 additions & 0 deletions src/Builder/Concerns/HasFile.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ trait HasFile
private bool $local = false;
private ?string $table = null;
private ?string $charset = null;
private ?string $extension = null;

public function file(string $file, ?bool $local = null): self
{
$this->file = $file;
$this->extension = strtolower(pathinfo($file, PATHINFO_EXTENSION));

if (isset($local)) {
$this->local($local);
Expand Down Expand Up @@ -57,4 +59,9 @@ public function getCharset(): ?string
{
return $this->charset;
}

public function isXML(): bool
{
return $this->extension === 'xml';
}
}
22 changes: 22 additions & 0 deletions src/Builder/Concerns/HasXmlRows.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace EllGreen\LaravelLoadFile\Builder\Concerns;

trait HasXmlRows
{
private string $rowIdentifier;

/**
* @param string $tag XML tag to identify rows, like: <item>
*/
public function rowIdentifiedBy(string $tag): self
{
$this->rowIdentifier = $tag;
return $this;
}

public function getRowIdentifier(): string
{
return $this->rowIdentifier;
}
}
30 changes: 20 additions & 10 deletions src/Grammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ public function compileLoadFile(Builder $query): CompiledQuery
throw CompilationException::noFileOrTableSupplied();
}

$querySegments->push('load data');
if ($query->isXML()) {
$querySegments->push('load xml');
} else {
$querySegments->push('load data');
}

if ($query->isLowPriority()) {
$querySegments->push('low_priority');
Expand Down Expand Up @@ -53,17 +57,23 @@ public function compileLoadFile(Builder $query): CompiledQuery
$querySegments->push('character set ' . $this->quoteString($charset));
}

$querySegments->push($this->compileFields(
$query->getFieldsTerminatedBy(),
$query->getFieldsEnclosedBy(),
$query->getFieldsEscapedBy(),
$query->getFieldsOptionallyEnclosed(),
));
if (!$query->isXML()) {
$querySegments->push($this->compileFields(
$query->getFieldsTerminatedBy(),
$query->getFieldsEnclosedBy(),
$query->getFieldsEscapedBy(),
$query->getFieldsOptionallyEnclosed(),
));

$querySegments->push($this->compileLines($query->getLinesStartingBy(), $query->getLinesTerminatedBy()));

$querySegments->push($this->compileLines($query->getLinesStartingBy(), $query->getLinesTerminatedBy()));
if ($query->getIgnoreLines() > 0) {
$querySegments->push("ignore {$query->getIgnoreLines()} lines");
}
}

if ($query->getIgnoreLines() > 0) {
$querySegments->push("ignore {$query->getIgnoreLines()} lines");
if ($query->isXML()) {
$querySegments->push('rows identified by ' . $this->quoteString($query->getRowIdentifier()));
}

$columns = $query->getColumns();
Expand Down
14 changes: 7 additions & 7 deletions tests/Feature/LoadFileTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class LoadFileTest extends TestCase
public function testSimpleLoad()
{
LoadFile::connection('mysql')
->file(realpath(__DIR__ . '/../data/people-simple.csv'), true)
->file(realpath(__DIR__ . '/../data/csv/people-simple.csv'), true)
->into('people')
->charset('utf8mb4')
->columns(['name', 'dob', 'greeting'])
Expand All @@ -23,7 +23,7 @@ public function testSimpleLoad()

public function testLoadWithSet()
{
LoadFile::file(realpath(__DIR__ . '/../data/people.csv'), true)
LoadFile::file(realpath(__DIR__ . '/../data/csv/people.csv'), true)
->into('people')
->columns([DB::raw('@forename'), DB::raw('@surname'), 'dob'])
->set([
Expand All @@ -49,7 +49,7 @@ public function testLoadWithSet()

public function testIgnoreRow()
{
LoadFile::file(realpath(__DIR__ . '/../data/people-simple.csv'), true)
LoadFile::file(realpath(__DIR__ . '/../data/csv/people-simple.csv'), true)
->into('people')
->ignoreLines(1)
->columns(['name', 'dob', 'greeting'])
Expand All @@ -71,7 +71,7 @@ public function testIgnoreRow()

public function testReplace()
{
LoadFile::file(realpath(__DIR__ . '/../data/people-simple.csv'), true)
LoadFile::file(realpath(__DIR__ . '/../data/csv/people-simple.csv'), true)
->replace()
->into('people')
->columns(['name', 'dob', 'greeting'])
Expand All @@ -83,7 +83,7 @@ public function testReplace()

public function testIgnore()
{
LoadFile::file(realpath(__DIR__ . '/../data/people-simple.csv'), true)
LoadFile::file(realpath(__DIR__ . '/../data/csv/people-simple.csv'), true)
->ignore()
->into('people')
->columns(['name', 'dob', 'greeting'])
Expand All @@ -95,7 +95,7 @@ public function testIgnore()

public function testLowPriority(): void
{
LoadFile::file(realpath(__DIR__ . '/../data/people-simple.csv'), true)
LoadFile::file(realpath(__DIR__ . '/../data/csv/people-simple.csv'), true)
->lowPriority()
->into('people')
->columns(['name', 'dob', 'greeting'])
Expand All @@ -107,7 +107,7 @@ public function testLowPriority(): void

public function testConcurrent(): void
{
LoadFile::file(realpath(__DIR__ . '/../data/people-simple.csv'), true)
LoadFile::file(realpath(__DIR__ . '/../data/csv/people-simple.csv'), true)
->concurrent()
->into('people')
->columns(['name', 'dob', 'greeting'])
Expand Down
138 changes: 138 additions & 0 deletions tests/Feature/LoadFileXMLTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<?php

namespace Feature;

use EllGreen\LaravelLoadFile\Laravel\Facades\LoadFile;
use Illuminate\Support\Facades\DB;
use Tests\Feature\TestCase;

class LoadFileXMLTest extends TestCase
{
public function testSimpleLoad()
{
LoadFile::connection('mysql')
->file(realpath(__DIR__ . '/../data/xml/people-simple.xml'), true)
->rowIdentifiedBy('<person>')
->into('people')
->charset('utf8mb4')
->columns(['name', 'dob', 'greeting'])
->load();

$this->assertJohnAndJaneExist();
}

public function testLoadWithSet()
{
LoadFile::file(realpath(__DIR__ . '/../data/xml/people.xml'), true)
->into('people')
->rowIdentifiedBy('<person>')
->columns([DB::raw('@forename'), DB::raw('@surname'), 'dob'])
->set([
'greeting' => 'Hello',
'name' => DB::raw("concat(@forename, ' ', @surname)"),
'imported_at' => DB::raw('current_timestamp'),
])
->load();

$this->assertDatabaseHas('people', [
'name' => 'John Doe',
'dob' => '1980-01-01',
'greeting' => 'Hello',
]);

$this->assertDatabaseHas('people', [
'name' => 'Jane Doe',
'dob' => '1975-06-30',
'greeting' => 'Hello',
]);
}

public function testIgnoreRow()
{
self::markTestSkipped('Add support for ignore rows');

LoadFile::file(realpath(__DIR__ . '/../data/xml/people-simple.xml'), true)
->into('people')
->ignoreLines(1)
->columns(['name', 'dob', 'greeting'])
->fields(',', '"', '\\\\', true)
->load();

$this->assertDatabaseMissing('people', [
'name' => 'John Doe',
'dob' => '1980-01-01',
'greeting' => 'Bonjour',
]);

$this->assertDatabaseHas('people', [
'name' => 'Jane Doe',
'dob' => '1975-06-30',
'greeting' => 'Hello',
]);
}

public function testReplace()
{
LoadFile::file(realpath(__DIR__ . '/../data/xml/people-simple.xml'), true)
->rowIdentifiedBy('<person>')
->replace()
->into('people')
->columns(['name', 'dob', 'greeting'])
->load();

$this->assertJohnAndJaneExist();
}

public function testIgnore()
{
LoadFile::file(realpath(__DIR__ . '/../data/xml/people-simple.xml'), true)
->rowIdentifiedBy('<person>')
->ignore()
->into('people')
->columns(['name', 'dob', 'greeting'])
->load();

$this->assertJohnAndJaneExist();
}

public function testLowPriority(): void
{
LoadFile::file(realpath(__DIR__ . '/../data/xml/people-simple.xml'), true)
->rowIdentifiedBy('<person>')
->lowPriority()
->into('people')
->columns(['name', 'dob', 'greeting'])
->fieldsTerminatedBy(',')
->load();

$this->assertJohnAndJaneExist();
}

public function testConcurrent(): void
{
LoadFile::file(realpath(__DIR__ . '/../data/xml/people-simple.xml'), true)
->rowIdentifiedBy('<person>')
->concurrent()
->into('people')
->columns(['name', 'dob', 'greeting'])
->fieldsTerminatedBy(',')
->load();

$this->assertJohnAndJaneExist();
}

private function assertJohnAndJaneExist(): void
{
$this->assertDatabaseHas('people', [
'name' => 'John Doe',
'dob' => '1980-01-01',
'greeting' => 'Bonjour',
]);

$this->assertDatabaseHas('people', [
'name' => 'Jane Doe',
'dob' => '1975-06-30',
'greeting' => 'Hello',
]);
}
}
File renamed without changes.
File renamed without changes.
13 changes: 13 additions & 0 deletions tests/data/xml/people-simple.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<people>
<person>
<name>John Doe</name>
<dob>1980-01-01</dob>
<greeting>Bonjour</greeting>
</person>
<person>
<name>Jane Doe</name>
<dob>1975-06-30</dob>
<greeting>Hello</greeting>
</person>
</people>
13 changes: 13 additions & 0 deletions tests/data/xml/people.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<people>
<person>
<forename>John</forename>
<surname>Doe</surname>
<dob>1980-01-01</dob>
</person>
<person>
<forename>Jane</forename>
<surname>Doe</surname>
<dob>1975-06-30</dob>
</person>
</people>