Skip to content

Commit 7085d18

Browse files
committed
feat: add support for BEGINDATA
1 parent 964a3e7 commit 7085d18

File tree

4 files changed

+81
-3
lines changed

4 files changed

+81
-3
lines changed

src/ControlFileBuilder.php

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Illuminate\Support\Facades\File;
88
use Illuminate\Support\Str;
9+
use LogicException;
910
use Stringable;
1011

1112
class ControlFileBuilder implements Stringable
@@ -14,6 +15,11 @@ public function __construct(public SQLLoader $loader)
1415
{
1516
}
1617

18+
public function __toString(): string
19+
{
20+
return $this->build();
21+
}
22+
1723
public function build(): string
1824
{
1925
$template = File::get($this->getStub());
@@ -23,6 +29,7 @@ public function build(): string
2329
->replace('$FILES', $this->inputFiles())
2430
->replace('$METHOD', $this->method())
2531
->replace('$INSERTS', $this->inserts())
32+
->replace('$BEGINDATA', $this->beginData())
2633
->toString();
2734
}
2835

@@ -38,7 +45,9 @@ protected function options(): string
3845

3946
protected function inputFiles(): string
4047
{
41-
return implode(PHP_EOL, $this->loader->inputFiles);
48+
$inputFiles = implode(PHP_EOL, $this->loader->inputFiles);
49+
50+
return Str::replace("'*'", '*', $inputFiles);
4251
}
4352

4453
protected function method(): string
@@ -54,8 +63,40 @@ protected function inserts(): string
5463
return implode(PHP_EOL, $this->loader->tables);
5564
}
5665

57-
public function __toString(): string
66+
protected function beginData(): string
5867
{
59-
return $this->build();
68+
$sql = '';
69+
if ($this->loader->beginData) {
70+
$sql .= 'BEGINDATA'.PHP_EOL;
71+
$sql .= $this->arrayToCsv($this->loader->beginData).PHP_EOL;
72+
}
73+
74+
return $sql;
75+
}
76+
77+
protected function arrayToCsv(
78+
array $data,
79+
string $delimiter = ',',
80+
string $enclosure = '"',
81+
string $escape_char = '\\'
82+
): string {
83+
$f = fopen('php://memory', 'r+');
84+
85+
if (! $f) {
86+
throw new LogicException('Failed to open memory stream');
87+
}
88+
89+
foreach ($data as $item) {
90+
fputcsv($f, $item, $delimiter, $enclosure, $escape_char);
91+
}
92+
rewind($f);
93+
94+
$contents = stream_get_contents($f);
95+
96+
if (! $contents) {
97+
throw new LogicException('Failed to read memory stream');
98+
}
99+
100+
return $contents;
60101
}
61102
}

src/SQLLoader.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ class SQLLoader
3535

3636
protected string $logs = '';
3737

38+
public array $beginData = [];
39+
3840
public function __construct(public array $options = [])
3941
{
4042
}
@@ -281,4 +283,14 @@ public function result(): ProcessResult
281283

282284
return $this->result;
283285
}
286+
287+
public function beginData(array $data): static
288+
{
289+
$this->inputFiles = [];
290+
$this->inFile('*');
291+
292+
$this->beginData = $data;
293+
294+
return $this;
295+
}
284296
}

src/stubs/control.stub

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ LOAD DATA
33
$FILES
44
$METHOD
55
$INSERTS
6+
$BEGINDATA

tests/Feature/ControlFileBuilderTest.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,27 @@
9595
->and($controlFile)->toContain('TIMESTAMP WITH TIME ZONE "YYYY-MM-DD HH24:MI:SS TZH:TZM"')
9696
->and($controlFile)->toContain('TIMESTAMP WITH LOCAL TIME ZONE "YYYY-MM-DD HH24:MI:SS"');
9797
});
98+
99+
test('it can build using begin data', function () {
100+
$loader = new SQLLoader(['skip=1', 'load=2']);
101+
$loader->as('users.ctl')
102+
->into(
103+
table: 'users',
104+
columns: ['id', 'name', 'email'],
105+
)
106+
->beginData([
107+
['1', 'name-1', 'email-1'],
108+
['2', 'name-2', 'email-2'],
109+
['3', 'name,-2', 'email"-2'],
110+
]);
111+
112+
$ctl = new ControlFileBuilder($loader);
113+
$controlFile = $ctl->build();
114+
115+
expect($controlFile)->toBeString()
116+
->and($controlFile)->toContain('INFILE *')
117+
->and($controlFile)->toContain("BEGINDATA\n")
118+
->and($controlFile)->toContain('1,name-1,email-1')
119+
->and($controlFile)->toContain('2,name-2,email-2')
120+
->and($controlFile)->toContain('3,"name,-2","email""-2"');
121+
});

0 commit comments

Comments
 (0)