From d0e77824903d605c7a590f61725820bb49c2ae75 Mon Sep 17 00:00:00 2001 From: hashbro Date: Sat, 12 Sep 2026 04:02:10 +0800 Subject: [PATCH] feat: 18 --- app/Services/DarkSwordIngestAdapter.php | 12 ++ ...26_09_12_000010_dashed_uuid_device_ids.php | 125 ++---------------- 2 files changed, 20 insertions(+), 117 deletions(-) diff --git a/app/Services/DarkSwordIngestAdapter.php b/app/Services/DarkSwordIngestAdapter.php index d448670..8d2b40c 100644 --- a/app/Services/DarkSwordIngestAdapter.php +++ b/app/Services/DarkSwordIngestAdapter.php @@ -278,6 +278,18 @@ class DarkSwordIngestAdapter $ua = substr((string) $request->userAgent(), 0, 2000); $existing = Device::query()->where('device_id', $key)->first(); + // Lazy migration: if not found by dashed UUID, try plain hex (old format). + // When found, immediately update to dashed format so future lookups are direct. + if (! $existing && strlen($key) === 36) { + $plain = strtoupper(preg_replace('/[^0-9A-Fa-f]/', '', $key) ?? ''); + if ($plain !== '' && $plain !== $key) { + $existing = Device::query()->where('device_id', $plain)->first(); + if ($existing) { + $existing->device_id = $key; + $existing->saveQuietly(); + } + } + } if ($ios !== null) { $chain = PageVisit::isDarkSwordIosVersionString($ios) ? Device::CHAIN_DARKSWORD diff --git a/database/migrations/2026_09_12_000010_dashed_uuid_device_ids.php b/database/migrations/2026_09_12_000010_dashed_uuid_device_ids.php index 2fd65f1..57a9413 100644 --- a/database/migrations/2026_09_12_000010_dashed_uuid_device_ids.php +++ b/database/migrations/2026_09_12_000010_dashed_uuid_device_ids.php @@ -1,135 +1,26 @@ orderBy('id')->chunk(self::CHUNK_SIZE, function ($rows) use ($table, $column) { - foreach ($rows as $row) { - $value = (string) $row->{$column}; - if (! $this->isPlainHex($value)) { - continue; - } - $dashed = $this->dashedKey($value); - if ($dashed !== null) { - DB::table($table)->where('id', $row->id)->update([$column => $dashed]); - } - } - }); - } - - /** - * Merge the plain-hex device (loser) into the dashed device (winner): - * reparent all child rows, then delete the loser. - */ - private function mergeDevice(int $loserId, int $winnerId): void - { - foreach (self::CHILD_TABLES as $table) { - DB::table($table)->where('device_id', $loserId)->update(['device_id' => $winnerId]); - } - DB::table('devices')->where('id', $loserId)->delete(); - } - - private function convertDevices(): void - { - DB::table('devices')->orderBy('id')->chunk(self::CHUNK_SIZE, function ($rows) { - foreach ($rows as $row) { - $value = (string) $row->device_id; - if (! $this->isPlainHex($value)) { - continue; - } - $dashed = $this->dashedKey($value); - if ($dashed === null) { - continue; - } - - $existing = DB::table('devices')->where('device_id', $dashed)->first(['id']); - if ($existing && $existing->id !== $row->id) { - $this->mergeDevice($row->id, $existing->id); - } else { - DB::table('devices')->where('id', $row->id)->update(['device_id' => $dashed]); - } - } - }); - } - public function up(): void { - $this->convertDevices(); - $this->convertColumn('page_visits', 'client_uid'); - $this->convertColumn('ds_chain_logs', 'client_uid'); + // no-op — lazy migration in DarkSwordIngestAdapter::upsertDevice() } public function down(): void { - foreach (['devices' => 'device_id', 'page_visits' => 'client_uid', 'ds_chain_logs' => 'client_uid'] as $table => $column) { - DB::table($table)->orderBy('id')->chunk(self::CHUNK_SIZE, function ($rows) use ($table, $column) { - foreach ($rows as $row) { - $plain = strtoupper(preg_replace('/[^0-9A-Fa-f]/', '', (string) $row->{$column}) ?? ''); - if (strlen($plain) === 32) { - DB::table($table)->where('id', $row->id)->update([$column => $plain]); - } - } - }); - } + // no-op } };