Upserter   A
last analyzed

Complexity

Total Complexity 7

Size/Duplication

Total Lines 73
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 7
eloc 37
c 0
b 0
f 0
dl 0
loc 73
ccs 41
cts 41
cp 1
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A upsert() 0 30 2
A implodedPlaceholders() 0 5 1
A convertInsertValues() 0 8 1
A addVersionToItems() 0 5 1
A updateSpec() 0 7 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Umbrellio\TableSync\Integration\Laravel\Receive\Upserter;
6
7
use Illuminate\Support\Arr;
8
use Illuminate\Support\Facades\DB;
9
use Umbrellio\TableSync\Integration\Laravel\Receive\MessageData\MessageData;
10
11
class Upserter
12
{
13
    private $conflictConditionResolver;
14
15 2
    public function __construct(ConflictConditionResolverContract $conflictConditionResolver)
16
    {
17 2
        $this->conflictConditionResolver = $conflictConditionResolver;
18
    }
19
20
    // todo via modern expressive not existing query builder
21 2
    public function upsert(MessageData $messageData, float $version): void
22
    {
23 2
        if (empty(array_filter($messageData->getData()))) {
24 1
            return;
25
        }
26
27 1
        $data = $this->addVersionToItems($messageData->getData(), $version);
28
29 1
        $columns = array_keys($data[0]);
30 1
        $columnString = implode(',', array_map(function (string $column): string {
31 1
            return "\"{$column}\"";
32 1
        }, $columns));
33
34 1
        $values = $this->convertInsertValues($data);
35 1
        $target = $this->conflictConditionResolver->resolve($messageData);
36
37 1
        $valueBindings = Arr::flatten($data);
38
39 1
        $updateColumns = array_diff($columns, $messageData->getTargetKeys());
40 1
        $updateSpecString = $this->updateSpec($updateColumns);
41
42 1
        $sql = <<<CODE_SAMPLE
43 1
        INSERT INTO {$messageData->getTable()} ({$columnString}) VALUES {$values}
44 1
        ON CONFLICT {$target} 
45
        DO UPDATE 
46 1
          SET {$updateSpecString}
47 1
          WHERE {$messageData->getTable()}.version < ?
48 1
CODE_SAMPLE;
49
50 1
        DB::statement($sql, array_merge($valueBindings, [$version]));
51
    }
52
53 1
    private function addVersionToItems(array $items, float $version): array
54
    {
55 1
        return array_map(function ($item) use ($version) {
56 1
            return array_merge($item, compact('version'));
57 1
        }, $items);
58
    }
59
60 1
    private function convertInsertValues(array $items): string
61
    {
62 1
        $values = array_map(function (array $item) {
63 1
            $item = $this->implodedPlaceholders($item);
64 1
            return "({$item})";
65 1
        }, $items);
66
67 1
        return implode(',', $values);
68
    }
69
70 1
    private function updateSpec(array $columns): string
71
    {
72 1
        $values = array_map(function (string $column) {
73 1
            return "\"{$column}\" = EXCLUDED.{$column}";
74 1
        }, $columns);
75
76 1
        return implode(',', $values);
77
    }
78
79 1
    private function implodedPlaceholders(array $items, string $placeholder = '?'): string
80
    {
81 1
        return implode(',', array_map(function () use ($placeholder) {
82 1
            return $placeholder;
83 1
        }, $items));
84
    }
85
}
86