67 lines
3.7 KiB
PHP
67 lines
3.7 KiB
PHP
<?php
|
||
|
||
namespace App\Console\Commands;
|
||
|
||
use Illuminate\Console\Command;
|
||
use Illuminate\Support\Facades\DB;
|
||
use Modules\EcommerceFinance\Services\UpstreamReadOnlyQueryFactory;
|
||
use Modules\EcommerceFinance\Services\UpstreamSourceRegistry;
|
||
use Modules\EcommerceFinance\Services\UpstreamSqlDialect;
|
||
use Throwable;
|
||
|
||
class InspectUpstream extends Command
|
||
{
|
||
protected $signature = 'upstream:inspect {source?} {schema?} {object?} {--columns= : 明确选择样本字段;不填时只显示字段目录} {--limit=5 : 样本上限,最多20行}';
|
||
protected $description = '通过统一驱动查看目录或有限只读样本,不生成快照或启动同步';
|
||
|
||
public function handle(UpstreamSourceRegistry $sources, UpstreamReadOnlyQueryFactory $queries): int
|
||
{
|
||
$source = (string) $this->argument('source');
|
||
$schema = (string) $this->argument('schema');
|
||
$object = (string) $this->argument('object');
|
||
try {
|
||
if ($source === '') {
|
||
$rows = [];
|
||
foreach ($sources->all() as $key => $definition) $rows[] = [$key, $definition['label'], $sources->driver($key), $sources->enabled($key) ? '启用' : '停用'];
|
||
$this->table(['内部标识', '数据库名称', '类型', '状态'], $rows);
|
||
return self::SUCCESS;
|
||
}
|
||
$sources->definition($source);
|
||
if ($schema === '' || $object === '') {
|
||
$objects = DB::table('upstream_schema_columns')->where('source_key', $source)
|
||
->when($schema !== '', fn ($q) => $q->where('schema_name', $schema))
|
||
->select('schema_name', 'object_name')->distinct()->orderBy('schema_name')->orderBy('object_name')->get();
|
||
$this->table(['Schema', '表 / 视图'], $objects->map(fn ($row) => [$row->schema_name, $row->object_name])->all());
|
||
return self::SUCCESS;
|
||
}
|
||
$catalog = DB::table('upstream_schema_columns')->where('source_key', $source)
|
||
->where('schema_name', $schema)->where('object_name', $object)->orderBy('ordinal_position')
|
||
->get(['column_name', 'data_type', 'is_nullable']);
|
||
if ($catalog->isEmpty()) {
|
||
$this->error('尚无该对象的字段目录,请先核实来源并同步数据字典。');
|
||
return self::FAILURE;
|
||
}
|
||
if (! $this->option('columns')) {
|
||
$this->table(['字段', '类型', '允许空值'], $catalog->map(fn ($c) => [$c->column_name, $c->data_type, $c->is_nullable ? '是' : '否'])->all());
|
||
return self::SUCCESS;
|
||
}
|
||
$columns = array_values(array_unique(array_filter(array_map('trim', explode(',', (string) $this->option('columns'))))));
|
||
if ($columns === [] || array_diff($columns, $catalog->pluck('column_name')->all())) {
|
||
$this->error('样本字段必须来自该对象的数据字典。');
|
||
return self::FAILURE;
|
||
}
|
||
$dialect = new UpstreamSqlDialect($sources->driver($source));
|
||
$sql = $dialect->select(implode(', ', array_map($dialect->quote(...), $columns)),
|
||
'FROM ' . $dialect->quote($schema) . '.' . $dialect->quote($object),
|
||
min(max((int) $this->option('limit'), 1), 20));
|
||
$rows = $queries->forSource($source)->select($sql);
|
||
$this->table($columns, array_map(fn ($row) => array_values($row), $rows));
|
||
$this->info('样本仅用于字段核实,不能作为完整业务数据。');
|
||
return self::SUCCESS;
|
||
} catch (Throwable) {
|
||
$this->error('只读检查未完成,请检查共享连接、来源启用状态和访问权限。');
|
||
return self::FAILURE;
|
||
}
|
||
}
|
||
}
|