connection = $database->connection( (string) config('upstream_mirrors.connection', 'business_mirror'), ); } /** @return array> */ public function policies(): array { return (array) config('business_data.datasets', []); } /** @return array */ public function policy(string $datasetKey): array { $policy = (array) ($this->policies()[$datasetKey] ?? []); if ($policy === []) { // Missing and runtime-registered connector datasets fail closed to // MariaDB. `business-data:plan` still fails CI/operations for a // missing code-owned policy, while a typo can never silently route // production data into ClickHouse. return [ 'role' => 'external_dimension', 'target_store' => 'mariadb', 'consumer' => '外部登记数据集', 'sync' => 'always', ]; } return $policy + ['sync' => 'always']; } public function targetStore(string $datasetKey): string { return (string) ($this->policy($datasetKey)['target_store'] ?? 'mariadb'); } public function shouldSchedule(string $datasetKey): bool { $sync = (string) ($this->policy($datasetKey)['sync'] ?? 'always'); return match ($sync) { 'always' => true, 'disabled' => false, 'after_columnar_activation' => $this->isActive($datasetKey, 'clickhouse'), default => throw new InvalidArgumentException('业务数据集同步策略无效:' . $datasetKey), }; } public function isActive(string $datasetKey, ?string $store = null): bool { $row = $this->state($datasetKey); if ($row === null || ($row['phase'] ?? null) !== 'active') { return false; } return $store === null || ($row['target_store'] ?? null) === $store; } /** @return array|null */ public function state(string $datasetKey): ?array { if (! Schema::connection($this->connection->getName())->hasTable('business_data_placements')) { return null; } $row = $this->connection->table('business_data_placements') ->where('dataset_key', $datasetKey) ->first(); return $row === null ? null : (array) $row; } /** @param array $values */ public function save(string $datasetKey, array $values): void { $now = now(); $this->connection->table('business_data_placements')->insertOrIgnore([ 'dataset_key' => $datasetKey, 'target_store' => $this->targetStore($datasetKey), 'phase' => 'planned', 'created_at' => $now, 'updated_at' => $now, ]); $this->connection->table('business_data_placements') ->where('dataset_key', $datasetKey) ->update(['updated_at' => $now] + $values); } public function connection(): ConnectionInterface { return $this->connection; } }