mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-29 23:53:57 +00:00
sql tree refactor
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import GridDisplay from "./GridDisplay";
|
import GridDisplay from "./GridDisplay";
|
||||||
import { Select } from "@dbgate/sqltree";
|
import { Select, treeToSql, dumpSqlSelect } from "@dbgate/sqltree";
|
||||||
import { TableInfo, EngineDriver } from "@dbgate/types";
|
import { TableInfo, EngineDriver } from "@dbgate/types";
|
||||||
import GridConfig from "./GridConfig";
|
import GridConfig from "./GridConfig";
|
||||||
|
|
||||||
@@ -14,9 +14,11 @@ export default class TableGridDisplay extends GridDisplay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createSelect() {
|
createSelect() {
|
||||||
const select = new Select();
|
const select: Select = {
|
||||||
select.from = this.table;
|
commandType: "select",
|
||||||
select.selectAll = true;
|
from: this.table,
|
||||||
|
selectAll: true
|
||||||
|
};
|
||||||
return select;
|
return select;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,7 +27,7 @@ export default class TableGridDisplay extends GridDisplay {
|
|||||||
if (this.driver.dialect.limitSelect) select.topRecords = count;
|
if (this.driver.dialect.limitSelect) select.topRecords = count;
|
||||||
if (this.driver.dialect.rangeSelect)
|
if (this.driver.dialect.rangeSelect)
|
||||||
select.range = { offset: offset, limit: count };
|
select.range = { offset: offset, limit: count };
|
||||||
const sql = select.toSql(this.driver);
|
const sql = treeToSql(this.driver, select, dumpSqlSelect);
|
||||||
return sql;
|
return sql;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
import { EngineDriver, SqlDumper } from "@dbgate/types";
|
import { NamedObjectInfo, RangeDefinition } from "@dbgate/types";
|
||||||
|
|
||||||
export class Command {
|
|
||||||
toSql(driver: EngineDriver) {
|
|
||||||
const dumper = driver.createDumper();
|
|
||||||
this.dumpSql(dumper);
|
|
||||||
return dumper.s;
|
|
||||||
}
|
|
||||||
|
|
||||||
dumpSql(dumper: SqlDumper) {}
|
// import { EngineDriver, SqlDumper } from "@dbgate/types";
|
||||||
}
|
|
||||||
|
// export class Command {
|
||||||
|
// toSql(driver: EngineDriver) {
|
||||||
|
// const dumper = driver.createDumper();
|
||||||
|
// this.dumpSql(dumper);
|
||||||
|
// return dumper.s;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// dumpSql(dumper: SqlDumper) {}
|
||||||
|
// }
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { SqlDumper } from "@dbgate/types";
|
// import { SqlDumper } from "@dbgate/types";
|
||||||
|
|
||||||
export abstract class Condition {
|
// export abstract class Condition {
|
||||||
abstract dumpSql(dumper: SqlDumper) ;
|
// abstract dumpSql(dumper: SqlDumper) ;
|
||||||
}
|
// }
|
||||||
|
|
||||||
export abstract class UnaryCondition extends Condition {
|
// export abstract class UnaryCondition extends Condition {
|
||||||
// expr: Expresssion;
|
// // expr: Expresssion;
|
||||||
}
|
// }
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
|
|
||||||
export abstract class Expression {
|
// export abstract class Expression {
|
||||||
|
|
||||||
}
|
// }
|
||||||
|
|||||||
@@ -1,29 +1,29 @@
|
|||||||
import { Command } from "./Command";
|
// import { Command } from "./Command";
|
||||||
import { NamedObjectInfo, RangeDefinition, SqlDumper } from "@dbgate/types";
|
// import { NamedObjectInfo, RangeDefinition, SqlDumper } from "@dbgate/types";
|
||||||
|
|
||||||
export class Select extends Command {
|
// export class Select extends Command {
|
||||||
topRecords: number;
|
// topRecords: number;
|
||||||
from: NamedObjectInfo;
|
// from: NamedObjectInfo;
|
||||||
range: RangeDefinition;
|
// range: RangeDefinition;
|
||||||
distinct = false;
|
// distinct = false;
|
||||||
selectAll = false;
|
// selectAll = false;
|
||||||
|
|
||||||
dumpSql(dumper: SqlDumper) {
|
// dumpSql(dumper: SqlDumper) {
|
||||||
dumper.put("^select ");
|
// dumper.put("^select ");
|
||||||
if (this.topRecords) {
|
// if (this.topRecords) {
|
||||||
dumper.put("^top %s ", this.topRecords);
|
// dumper.put("^top %s ", this.topRecords);
|
||||||
}
|
// }
|
||||||
if (this.distinct) {
|
// if (this.distinct) {
|
||||||
dumper.put("^distinct ");
|
// dumper.put("^distinct ");
|
||||||
}
|
// }
|
||||||
if (this.selectAll) {
|
// if (this.selectAll) {
|
||||||
dumper.put("* ");
|
// dumper.put("* ");
|
||||||
} else {
|
// } else {
|
||||||
// TODO
|
// // TODO
|
||||||
}
|
// }
|
||||||
dumper.put("^from %f ", this.from);
|
// dumper.put("^from %f ", this.from);
|
||||||
if (this.range) {
|
// if (this.range) {
|
||||||
dumper.put("^limit %s ^offset %s ", this.range.limit, this.range.offset);
|
// dumper.put("^limit %s ^offset %s ", this.range.limit, this.range.offset);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|||||||
@@ -1,78 +1,78 @@
|
|||||||
import { SqlDumper, NamedObjectInfo } from "@dbgate/types";
|
// import { SqlDumper, NamedObjectInfo } from "@dbgate/types";
|
||||||
import { Select } from "./Select";
|
// import { Select } from "./Select";
|
||||||
|
|
||||||
export class Source {
|
// export class Source {
|
||||||
name: NamedObjectInfo;
|
// name: NamedObjectInfo;
|
||||||
alias: string;
|
// alias: string;
|
||||||
subQuery: Select;
|
// subQuery: Select;
|
||||||
subQueryString: string;
|
// subQueryString: string;
|
||||||
|
|
||||||
dumpSqlDef(dumper: SqlDumper) {
|
// dumpSqlDef(dumper: SqlDumper) {
|
||||||
let sources = 0;
|
// let sources = 0;
|
||||||
if (this.name != null) sources++;
|
// if (this.name != null) sources++;
|
||||||
if (this.subQuery != null) sources++;
|
// if (this.subQuery != null) sources++;
|
||||||
if (this.subQueryString != null) sources++;
|
// if (this.subQueryString != null) sources++;
|
||||||
if (sources != 1)
|
// if (sources != 1)
|
||||||
throw new Error("sqltree.Source should have exactly one source");
|
// throw new Error("sqltree.Source should have exactly one source");
|
||||||
|
|
||||||
if (this.name != null) {
|
// if (this.name != null) {
|
||||||
dumper.put("%f", this.name);
|
// dumper.put("%f", this.name);
|
||||||
}
|
// }
|
||||||
if (this.subQuery) {
|
// if (this.subQuery) {
|
||||||
dumper.put("(");
|
// dumper.put("(");
|
||||||
this.subQuery.dumpSql(dumper);
|
// this.subQuery.dumpSql(dumper);
|
||||||
dumper.put(")");
|
// dumper.put(")");
|
||||||
}
|
// }
|
||||||
if (this.subQueryString) {
|
// if (this.subQueryString) {
|
||||||
dumper.put("(");
|
// dumper.put("(");
|
||||||
dumper.putRaw(this.subQueryString);
|
// dumper.putRaw(this.subQueryString);
|
||||||
dumper.put(")");
|
// dumper.put(")");
|
||||||
}
|
// }
|
||||||
if (this.alias) {
|
// if (this.alias) {
|
||||||
dumper.put(" %i", this.alias);
|
// dumper.put(" %i", this.alias);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
dumpSqlRef(dumper: SqlDumper) {
|
// dumpSqlRef(dumper: SqlDumper) {
|
||||||
if (this.alias != null) {
|
// if (this.alias != null) {
|
||||||
dumper.put("%i", this.alias);
|
// dumper.put("%i", this.alias);
|
||||||
return true;
|
// return true;
|
||||||
} else if (this.name != null) {
|
// } else if (this.name != null) {
|
||||||
dumper.put("%f", this.name);
|
// dumper.put("%f", this.name);
|
||||||
return true;
|
// return true;
|
||||||
}
|
// }
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
class Relation {
|
// class Relation {
|
||||||
source:Source;
|
// source:Source;
|
||||||
joinType: string;
|
// joinType: string;
|
||||||
// conditions:
|
// // conditions:
|
||||||
|
|
||||||
|
|
||||||
// dumpSqlRef(dumper: SqlDumper) {
|
// // dumpSqlRef(dumper: SqlDumper) {
|
||||||
|
|
||||||
// dumper.put("&n");
|
// // dumper.put("&n");
|
||||||
// dumper.putRaw(this.joinType);
|
// // dumper.putRaw(this.joinType);
|
||||||
// dumper.put(" ");
|
// // dumper.put(" ");
|
||||||
// this.source.dumpSqlDef(dumper)
|
// // this.source.dumpSqlDef(dumper)
|
||||||
// if (Conditions.Any())
|
// // if (Conditions.Any())
|
||||||
// {
|
// // {
|
||||||
// dumper.put(" ^on ");
|
// // dumper.put(" ^on ");
|
||||||
// bool was = false;
|
// // bool was = false;
|
||||||
// foreach (var cond in Conditions)
|
// // foreach (var cond in Conditions)
|
||||||
// {
|
// // {
|
||||||
// if (was) dumper.put(" ^and ");
|
// // if (was) dumper.put(" ^and ");
|
||||||
// cond.GenSql(dmp);
|
// // cond.GenSql(dmp);
|
||||||
// was = true;
|
// // was = true;
|
||||||
// }
|
// // }
|
||||||
// }
|
// // }
|
||||||
// }
|
// // }
|
||||||
|
|
||||||
}
|
// }
|
||||||
|
|
||||||
export class FromDefinition {
|
// export class FromDefinition {
|
||||||
source: Source;
|
// source: Source;
|
||||||
relations: Relation[] = [];
|
// relations: Relation[] = [];
|
||||||
}
|
// }
|
||||||
|
|||||||
29
packages/sqltree/src/dumpSqlCommand.ts
Normal file
29
packages/sqltree/src/dumpSqlCommand.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { SqlDumper } from "@dbgate/types";
|
||||||
|
import { Command, Select } from "./types";
|
||||||
|
|
||||||
|
export function dumpSqlSelect(dmp: SqlDumper, select: Select) {
|
||||||
|
dmp.put("^select ");
|
||||||
|
if (select.topRecords) {
|
||||||
|
dmp.put("^top %s ", select.topRecords);
|
||||||
|
}
|
||||||
|
if (select.distinct) {
|
||||||
|
dmp.put("^distinct ");
|
||||||
|
}
|
||||||
|
if (select.selectAll) {
|
||||||
|
dmp.put("* ");
|
||||||
|
} else {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
dmp.put("^from %f ", select.from);
|
||||||
|
if (select.range) {
|
||||||
|
dmp.put("^limit %s ^offset %s ", select.range.limit, select.range.offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dumpSqlCommand(dmp: SqlDumper, command: Command) {
|
||||||
|
switch (command.commandType) {
|
||||||
|
case "select":
|
||||||
|
dumpSqlSelect(dmp, command as Select);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
20
packages/sqltree/src/dumpSqlExpression.ts
Normal file
20
packages/sqltree/src/dumpSqlExpression.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { SqlDumper } from "@dbgate/types";
|
||||||
|
import { Expression, ColumnRefExpression } from "./types";
|
||||||
|
import { dumpSqlSourceRef } from "./dumpSqlSource";
|
||||||
|
|
||||||
|
function dumpSqlColumnRef(dumper: SqlDumper, expr: ColumnRefExpression) {
|
||||||
|
if (expr.source) {
|
||||||
|
if (dumpSqlSourceRef(dumper, expr.source)) {
|
||||||
|
dumper.put(".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dumper.put("%i", expr.columnName);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dumpSqlExpression(dumper: SqlDumper, expr: Expression) {
|
||||||
|
switch (expr.exprType) {
|
||||||
|
case "column":
|
||||||
|
dumpSqlColumnRef(dumper, expr as ColumnRefExpression);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
40
packages/sqltree/src/dumpSqlSource.ts
Normal file
40
packages/sqltree/src/dumpSqlSource.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { Source } from "./types";
|
||||||
|
import { SqlDumper } from "@dbgate/types";
|
||||||
|
import { dumpSqlSelect } from "./dumpSqlCommand";
|
||||||
|
|
||||||
|
export function dumpSqlSourceDef(dmp: SqlDumper, source: Source) {
|
||||||
|
let sources = 0;
|
||||||
|
if (source.name != null) sources++;
|
||||||
|
if (source.subQuery != null) sources++;
|
||||||
|
if (source.subQueryString != null) sources++;
|
||||||
|
if (sources != 1)
|
||||||
|
throw new Error("sqltree.Source should have exactly one source");
|
||||||
|
|
||||||
|
if (source.name != null) {
|
||||||
|
dmp.put("%f", source.name);
|
||||||
|
}
|
||||||
|
if (source.subQuery) {
|
||||||
|
dmp.put("(");
|
||||||
|
dumpSqlSelect(dmp, source.subQuery);
|
||||||
|
dmp.put(")");
|
||||||
|
}
|
||||||
|
if (source.subQueryString) {
|
||||||
|
dmp.put("(");
|
||||||
|
dmp.putRaw(source.subQueryString);
|
||||||
|
dmp.put(")");
|
||||||
|
}
|
||||||
|
if (source.alias) {
|
||||||
|
dmp.put(" %i", this.alias);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dumpSqlSourceRef(dmp: SqlDumper, source: Source) {
|
||||||
|
if (source.alias) {
|
||||||
|
dmp.put("%i", source.alias);
|
||||||
|
return true;
|
||||||
|
} else if (source.name) {
|
||||||
|
dmp.put("%f", source.name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
export { Select } from "./Select";
|
export * from "./types";
|
||||||
export { Command } from "./Command";
|
export * from "./dumpSqlCommand";
|
||||||
|
export * from "./treeToSql";
|
||||||
|
|||||||
11
packages/sqltree/src/treeToSql.ts
Normal file
11
packages/sqltree/src/treeToSql.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { EngineDriver, SqlDumper } from "@dbgate/types";
|
||||||
|
|
||||||
|
export function treeToSql<T>(
|
||||||
|
driver: EngineDriver,
|
||||||
|
object: T,
|
||||||
|
func: (dmp: SqlDumper, obj: T) => void
|
||||||
|
) {
|
||||||
|
const dmp = driver.createDumper();
|
||||||
|
func(dmp, object);
|
||||||
|
return dmp.s;
|
||||||
|
}
|
||||||
62
packages/sqltree/src/types.ts
Normal file
62
packages/sqltree/src/types.ts
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
import { NamedObjectInfo, RangeDefinition } from "@dbgate/types";
|
||||||
|
|
||||||
|
export interface Command {
|
||||||
|
commandType: "select";
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Select extends Command {
|
||||||
|
from: NamedObjectInfo;
|
||||||
|
|
||||||
|
topRecords?: number;
|
||||||
|
range?: RangeDefinition;
|
||||||
|
distinct?: boolean;
|
||||||
|
selectAll?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Condition {
|
||||||
|
conditionType: "eq" | "not";
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UnaryCondition extends Condition {
|
||||||
|
expr: Expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BinaryCondition extends Condition {
|
||||||
|
left: Expression;
|
||||||
|
right: Expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NotCondition extends UnaryCondition {
|
||||||
|
conditionType: "not";
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Source {
|
||||||
|
name: NamedObjectInfo;
|
||||||
|
alias: string;
|
||||||
|
subQuery: Select;
|
||||||
|
subQueryString: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type JoinType = "LEFT JOIN" | "INNER JOIN" | "RIGHT JOIN";
|
||||||
|
|
||||||
|
export interface Relation {
|
||||||
|
source: Source;
|
||||||
|
conditions: Condition[];
|
||||||
|
joinType: JoinType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Expression {
|
||||||
|
exprType: "column" | "value" | "string" | "literal" | "count";
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ColumnRefExpression extends Expression {
|
||||||
|
exprType: "column";
|
||||||
|
columnName: string;
|
||||||
|
source: Source;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ValueExpression extends Expression {
|
||||||
|
exprType: "value";
|
||||||
|
value: any;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -11,8 +11,8 @@ export default function TableCreateScriptTab({ conid, database, schemaName, pure
|
|||||||
// console.log(tableInfo);
|
// console.log(tableInfo);
|
||||||
|
|
||||||
const driver = engines(connnection.engine);
|
const driver = engines(connnection.engine);
|
||||||
const dumper = driver.createDumper();
|
const dmp = driver.createDumper();
|
||||||
if (tableInfo) dumper.createTable(tableInfo);
|
if (tableInfo) dmp.createTable(tableInfo);
|
||||||
|
|
||||||
return <SqlEditor engine={connnection && connnection.engine} value={dumper.s} />;
|
return <SqlEditor engine={connnection && connnection.engine} value={dmp.s} />;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user