mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-05-20 23:59:56 +08:00
- 后端实现:新增Redis客户端接口与go-redis实现,支持SSH隧道连接 - API方法:新增21个Redis操作API(连接/Key/Value/命令执行等) - 连接配置:ConnectionModal支持Redis类型,自动识别端口与认证方式 - 数据浏览:RedisViewer组件支持Key列表展示、类型识别与分页加载 - 值编辑器:支持String/Hash/List/Set/ZSet五种数据类型的查看与编辑 - 二进制处理:自动检测二进制数据并以十六进制格式展示 - 命令终端:RedisCommandEditor支持多行命令执行与结果展示 - 交互优化:JSON语法高亮编辑、一键复制值、面板宽度可调整
259 lines
7.1 KiB
TypeScript
Executable File
259 lines
7.1 KiB
TypeScript
Executable File
export namespace connection {
|
|
|
|
export class UpdateRow {
|
|
keys: Record<string, any>;
|
|
values: Record<string, any>;
|
|
|
|
static createFrom(source: any = {}) {
|
|
return new UpdateRow(source);
|
|
}
|
|
|
|
constructor(source: any = {}) {
|
|
if ('string' === typeof source) source = JSON.parse(source);
|
|
this.keys = source["keys"];
|
|
this.values = source["values"];
|
|
}
|
|
}
|
|
export class ChangeSet {
|
|
inserts: any[];
|
|
updates: UpdateRow[];
|
|
deletes: any[];
|
|
|
|
static createFrom(source: any = {}) {
|
|
return new ChangeSet(source);
|
|
}
|
|
|
|
constructor(source: any = {}) {
|
|
if ('string' === typeof source) source = JSON.parse(source);
|
|
this.inserts = source["inserts"];
|
|
this.updates = this.convertValues(source["updates"], UpdateRow);
|
|
this.deletes = source["deletes"];
|
|
}
|
|
|
|
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
|
if (!a) {
|
|
return a;
|
|
}
|
|
if (a.slice && a.map) {
|
|
return (a as any[]).map(elem => this.convertValues(elem, classs));
|
|
} else if ("object" === typeof a) {
|
|
if (asMap) {
|
|
for (const key of Object.keys(a)) {
|
|
a[key] = new classs(a[key]);
|
|
}
|
|
return a;
|
|
}
|
|
return new classs(a);
|
|
}
|
|
return a;
|
|
}
|
|
}
|
|
export class SSHConfig {
|
|
host: string;
|
|
port: number;
|
|
user: string;
|
|
password: string;
|
|
keyPath: string;
|
|
|
|
static createFrom(source: any = {}) {
|
|
return new SSHConfig(source);
|
|
}
|
|
|
|
constructor(source: any = {}) {
|
|
if ('string' === typeof source) source = JSON.parse(source);
|
|
this.host = source["host"];
|
|
this.port = source["port"];
|
|
this.user = source["user"];
|
|
this.password = source["password"];
|
|
this.keyPath = source["keyPath"];
|
|
}
|
|
}
|
|
export class ConnectionConfig {
|
|
type: string;
|
|
host: string;
|
|
port: number;
|
|
user: string;
|
|
password: string;
|
|
database: string;
|
|
useSSH: boolean;
|
|
ssh: SSHConfig;
|
|
driver?: string;
|
|
dsn?: string;
|
|
timeout?: number;
|
|
redisDB?: number;
|
|
|
|
static createFrom(source: any = {}) {
|
|
return new ConnectionConfig(source);
|
|
}
|
|
|
|
constructor(source: any = {}) {
|
|
if ('string' === typeof source) source = JSON.parse(source);
|
|
this.type = source["type"];
|
|
this.host = source["host"];
|
|
this.port = source["port"];
|
|
this.user = source["user"];
|
|
this.password = source["password"];
|
|
this.database = source["database"];
|
|
this.useSSH = source["useSSH"];
|
|
this.ssh = this.convertValues(source["ssh"], SSHConfig);
|
|
this.driver = source["driver"];
|
|
this.dsn = source["dsn"];
|
|
this.timeout = source["timeout"];
|
|
this.redisDB = source["redisDB"];
|
|
}
|
|
|
|
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
|
if (!a) {
|
|
return a;
|
|
}
|
|
if (a.slice && a.map) {
|
|
return (a as any[]).map(elem => this.convertValues(elem, classs));
|
|
} else if ("object" === typeof a) {
|
|
if (asMap) {
|
|
for (const key of Object.keys(a)) {
|
|
a[key] = new classs(a[key]);
|
|
}
|
|
return a;
|
|
}
|
|
return new classs(a);
|
|
}
|
|
return a;
|
|
}
|
|
}
|
|
export class QueryResult {
|
|
success: boolean;
|
|
message: string;
|
|
data: any;
|
|
fields?: string[];
|
|
|
|
static createFrom(source: any = {}) {
|
|
return new QueryResult(source);
|
|
}
|
|
|
|
constructor(source: any = {}) {
|
|
if ('string' === typeof source) source = JSON.parse(source);
|
|
this.success = source["success"];
|
|
this.message = source["message"];
|
|
this.data = source["data"];
|
|
this.fields = source["fields"];
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
export namespace redis {
|
|
|
|
export class ZSetMember {
|
|
member: string;
|
|
score: number;
|
|
|
|
static createFrom(source: any = {}) {
|
|
return new ZSetMember(source);
|
|
}
|
|
|
|
constructor(source: any = {}) {
|
|
if ('string' === typeof source) source = JSON.parse(source);
|
|
this.member = source["member"];
|
|
this.score = source["score"];
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
export namespace sync {
|
|
|
|
export class TableOptions {
|
|
insert?: boolean;
|
|
update?: boolean;
|
|
delete?: boolean;
|
|
selectedInsertPks?: string[];
|
|
selectedUpdatePks?: string[];
|
|
selectedDeletePks?: string[];
|
|
|
|
static createFrom(source: any = {}) {
|
|
return new TableOptions(source);
|
|
}
|
|
|
|
constructor(source: any = {}) {
|
|
if ('string' === typeof source) source = JSON.parse(source);
|
|
this.insert = source["insert"];
|
|
this.update = source["update"];
|
|
this.delete = source["delete"];
|
|
this.selectedInsertPks = source["selectedInsertPks"];
|
|
this.selectedUpdatePks = source["selectedUpdatePks"];
|
|
this.selectedDeletePks = source["selectedDeletePks"];
|
|
}
|
|
}
|
|
export class SyncConfig {
|
|
sourceConfig: connection.ConnectionConfig;
|
|
targetConfig: connection.ConnectionConfig;
|
|
tables: string[];
|
|
content?: string;
|
|
mode: string;
|
|
jobId?: string;
|
|
autoAddColumns?: boolean;
|
|
tableOptions?: Record<string, TableOptions>;
|
|
|
|
static createFrom(source: any = {}) {
|
|
return new SyncConfig(source);
|
|
}
|
|
|
|
constructor(source: any = {}) {
|
|
if ('string' === typeof source) source = JSON.parse(source);
|
|
this.sourceConfig = this.convertValues(source["sourceConfig"], connection.ConnectionConfig);
|
|
this.targetConfig = this.convertValues(source["targetConfig"], connection.ConnectionConfig);
|
|
this.tables = source["tables"];
|
|
this.content = source["content"];
|
|
this.mode = source["mode"];
|
|
this.jobId = source["jobId"];
|
|
this.autoAddColumns = source["autoAddColumns"];
|
|
this.tableOptions = this.convertValues(source["tableOptions"], TableOptions, true);
|
|
}
|
|
|
|
convertValues(a: any, classs: any, asMap: boolean = false): any {
|
|
if (!a) {
|
|
return a;
|
|
}
|
|
if (a.slice && a.map) {
|
|
return (a as any[]).map(elem => this.convertValues(elem, classs));
|
|
} else if ("object" === typeof a) {
|
|
if (asMap) {
|
|
for (const key of Object.keys(a)) {
|
|
a[key] = new classs(a[key]);
|
|
}
|
|
return a;
|
|
}
|
|
return new classs(a);
|
|
}
|
|
return a;
|
|
}
|
|
}
|
|
export class SyncResult {
|
|
success: boolean;
|
|
message: string;
|
|
logs: string[];
|
|
tablesSynced: number;
|
|
rowsInserted: number;
|
|
rowsUpdated: number;
|
|
rowsDeleted: number;
|
|
|
|
static createFrom(source: any = {}) {
|
|
return new SyncResult(source);
|
|
}
|
|
|
|
constructor(source: any = {}) {
|
|
if ('string' === typeof source) source = JSON.parse(source);
|
|
this.success = source["success"];
|
|
this.message = source["message"];
|
|
this.logs = source["logs"];
|
|
this.tablesSynced = source["tablesSynced"];
|
|
this.rowsInserted = source["rowsInserted"];
|
|
this.rowsUpdated = source["rowsUpdated"];
|
|
this.rowsDeleted = source["rowsDeleted"];
|
|
}
|
|
}
|
|
|
|
}
|
|
|