mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-28 02:36:01 +00:00
filter parser connected
This commit is contained in:
@@ -1,8 +1,9 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { GridConfig, GridCache, GridConfigColumns } from './GridConfig';
|
import { GridConfig, GridCache, GridConfigColumns } from './GridConfig';
|
||||||
import { ForeignKeyInfo, TableInfo, ColumnInfo } from '@dbgate/types';
|
import { ForeignKeyInfo, TableInfo, ColumnInfo, DbType } from '@dbgate/types';
|
||||||
|
import { parseFilter, getFilterType } from '@dbgate/filterparser';
|
||||||
import { filterName } from './filterName';
|
import { filterName } from './filterName';
|
||||||
import { Select } from '@dbgate/sqltree';
|
import { Select, Expression } from '@dbgate/sqltree';
|
||||||
|
|
||||||
export interface DisplayColumn {
|
export interface DisplayColumn {
|
||||||
schemaName: string;
|
schemaName: string;
|
||||||
@@ -17,6 +18,15 @@ export interface DisplayColumn {
|
|||||||
foreignKey: ForeignKeyInfo;
|
foreignKey: ForeignKeyInfo;
|
||||||
isChecked?: boolean;
|
isChecked?: boolean;
|
||||||
hintColumnName?: string;
|
hintColumnName?: string;
|
||||||
|
commonType?: DbType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DisplayedColumnEx extends DisplayColumn {
|
||||||
|
sourceAlias: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DisplayedColumnInfo {
|
||||||
|
[uniqueName: string]: DisplayedColumnEx;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ReferenceActionResult = 'noAction' | 'loadRequired' | 'refAdded';
|
export type ReferenceActionResult = 'noAction' | 'loadRequired' | 'refAdded';
|
||||||
@@ -143,7 +153,12 @@ export abstract class GridDisplay {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
addAddedColumnsToSelect(select: Select, columns: DisplayColumn[], parentAlias: string): ReferenceActionResult {
|
addAddedColumnsToSelect(
|
||||||
|
select: Select,
|
||||||
|
columns: DisplayColumn[],
|
||||||
|
parentAlias: string,
|
||||||
|
displayedColumnInfo: DisplayedColumnInfo
|
||||||
|
): ReferenceActionResult {
|
||||||
let res: ReferenceActionResult = 'noAction';
|
let res: ReferenceActionResult = 'noAction';
|
||||||
for (const column of columns) {
|
for (const column of columns) {
|
||||||
if (this.config.addedColumns.includes(column.uniqueName)) {
|
if (this.config.addedColumns.includes(column.uniqueName)) {
|
||||||
@@ -153,13 +168,22 @@ export abstract class GridDisplay {
|
|||||||
alias: column.uniqueName,
|
alias: column.uniqueName,
|
||||||
source: { name: column, alias: parentAlias },
|
source: { name: column, alias: parentAlias },
|
||||||
});
|
});
|
||||||
|
displayedColumnInfo[column.uniqueName] = {
|
||||||
|
...column,
|
||||||
|
sourceAlias: parentAlias,
|
||||||
|
};
|
||||||
res = 'refAdded';
|
res = 'refAdded';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
addJoinsFromExpandedColumns(select: Select, columns: DisplayColumn[], parentAlias: string): ReferenceActionResult {
|
addJoinsFromExpandedColumns(
|
||||||
|
select: Select,
|
||||||
|
columns: DisplayColumn[],
|
||||||
|
parentAlias: string,
|
||||||
|
columnSources
|
||||||
|
): ReferenceActionResult {
|
||||||
let res: ReferenceActionResult = 'noAction';
|
let res: ReferenceActionResult = 'noAction';
|
||||||
for (const column of columns) {
|
for (const column of columns) {
|
||||||
if (this.isExpandedColumn(column.uniqueName)) {
|
if (this.isExpandedColumn(column.uniqueName)) {
|
||||||
@@ -168,8 +192,8 @@ export abstract class GridDisplay {
|
|||||||
const childAlias = `${column.uniqueName}_ref`;
|
const childAlias = `${column.uniqueName}_ref`;
|
||||||
const subcolumns = this.getDisplayColumns(table, column.uniquePath);
|
const subcolumns = this.getDisplayColumns(table, column.uniquePath);
|
||||||
const tableAction = combineReferenceActions(
|
const tableAction = combineReferenceActions(
|
||||||
this.addJoinsFromExpandedColumns(select, subcolumns, childAlias),
|
this.addJoinsFromExpandedColumns(select, subcolumns, childAlias, columnSources),
|
||||||
this.addAddedColumnsToSelect(select, subcolumns, childAlias)
|
this.addAddedColumnsToSelect(select, subcolumns, childAlias, columnSources)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (tableAction == 'refAdded') {
|
if (tableAction == 'refAdded') {
|
||||||
@@ -247,6 +271,26 @@ export abstract class GridDisplay {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applyFilterOnSelect(select: Select, displayedColumnInfo: DisplayedColumnInfo) {
|
||||||
|
for (const uniqueName in this.config.filters) {
|
||||||
|
const filter = this.config.filters[uniqueName];
|
||||||
|
if (!filter) continue;
|
||||||
|
const column = displayedColumnInfo[uniqueName];
|
||||||
|
if (!column) continue;
|
||||||
|
const condition = parseFilter(filter, getFilterType(column.commonType?.typeCode));
|
||||||
|
if (condition) {
|
||||||
|
select.where = _.cloneDeepWith(condition, (expr: Expression) => {
|
||||||
|
if (expr.exprType == 'placeholder')
|
||||||
|
return {
|
||||||
|
exprType: 'column',
|
||||||
|
columnName: column.columnName,
|
||||||
|
source: { alias: column.sourceAlias },
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
getDisplayColumns(table: TableInfo, parentPath: string[]) {
|
getDisplayColumns(table: TableInfo, parentPath: string[]) {
|
||||||
return (
|
return (
|
||||||
table?.columns
|
table?.columns
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import _ from 'lodash'
|
||||||
import { GridDisplay, combineReferenceActions } from './GridDisplay';
|
import { GridDisplay, combineReferenceActions } from './GridDisplay';
|
||||||
import { Select, treeToSql, dumpSqlSelect } from '@dbgate/sqltree';
|
import { Select, treeToSql, dumpSqlSelect } from '@dbgate/sqltree';
|
||||||
import { TableInfo, EngineDriver } from '@dbgate/types';
|
import { TableInfo, EngineDriver } from '@dbgate/types';
|
||||||
@@ -37,10 +38,15 @@ export class TableGridDisplay extends GridDisplay {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
const displayedColumnInfo = _.keyBy(
|
||||||
|
this.columns.map(col => ({ ...col, sourceAlias: 'basetbl' })),
|
||||||
|
'uniqueName'
|
||||||
|
);
|
||||||
const action = combineReferenceActions(
|
const action = combineReferenceActions(
|
||||||
this.addJoinsFromExpandedColumns(select, this.columns, 'basetbl'),
|
this.addJoinsFromExpandedColumns(select, this.columns, 'basetbl', displayedColumnInfo),
|
||||||
this.addHintsToSelect(select)
|
this.addHintsToSelect(select)
|
||||||
);
|
);
|
||||||
|
this.applyFilterOnSelect(select, displayedColumnInfo);
|
||||||
if (action == 'loadRequired') {
|
if (action == 'loadRequired') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,52 +1,176 @@
|
|||||||
const fp = require("lodash/fp");
|
const fp = require('lodash/fp');
|
||||||
const _ = require("lodash");
|
const _ = require('lodash');
|
||||||
|
|
||||||
const DatabaseAnalayser = require("../default/DatabaseAnalyser");
|
const DatabaseAnalayser = require('../default/DatabaseAnalyser');
|
||||||
|
|
||||||
/** @returns {Promise<string>} */
|
/** @returns {Promise<string>} */
|
||||||
async function loadQuery(pool, name) {
|
async function loadQuery(pool, name) {
|
||||||
return await pool._nativeModules.fs.readFile(
|
return await pool._nativeModules.fs.readFile(pool._nativeModules.path.join(__dirname, name), 'utf-8');
|
||||||
pool._nativeModules.path.join(__dirname, name),
|
|
||||||
"utf-8"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const byTableFilter = table => x =>
|
const byTableFilter = table => x => x.pureName == table.pureName && x.schemaName == x.schemaName;
|
||||||
x.pureName == table.pureName && x.schemaName == x.schemaName;
|
|
||||||
|
|
||||||
function extractPrimaryKeys(table, pkColumns) {
|
function extractPrimaryKeys(table, pkColumns) {
|
||||||
const filtered = pkColumns.filter(byTableFilter(table));
|
const filtered = pkColumns.filter(byTableFilter(table));
|
||||||
if (filtered.length == 0) return undefined;
|
if (filtered.length == 0) return undefined;
|
||||||
return {
|
return {
|
||||||
..._.pick(filtered[0], ["constraintName", "schemaName", "pureName"]),
|
..._.pick(filtered[0], ['constraintName', 'schemaName', 'pureName']),
|
||||||
constraintType: "primaryKey",
|
constraintType: 'primaryKey',
|
||||||
columns: filtered.map(fp.pick("columnName"))
|
columns: filtered.map(fp.pick('columnName')),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractForeignKeys(table, fkColumns) {
|
function extractForeignKeys(table, fkColumns) {
|
||||||
const grouped = _.groupBy(
|
const grouped = _.groupBy(fkColumns.filter(byTableFilter(table)), 'constraintName');
|
||||||
fkColumns.filter(byTableFilter(table)),
|
|
||||||
"constraintName"
|
|
||||||
);
|
|
||||||
return _.keys(grouped).map(constraintName => ({
|
return _.keys(grouped).map(constraintName => ({
|
||||||
constraintName,
|
constraintName,
|
||||||
constraintType: "foreignKey",
|
constraintType: 'foreignKey',
|
||||||
..._.pick(grouped[constraintName][0], [
|
..._.pick(grouped[constraintName][0], [
|
||||||
"constraintName",
|
'constraintName',
|
||||||
"schemaName",
|
'schemaName',
|
||||||
"pureName",
|
'pureName',
|
||||||
"refSchemaName",
|
'refSchemaName',
|
||||||
"refTableName",
|
'refTableName',
|
||||||
"updateAction",
|
'updateAction',
|
||||||
"deleteAction"
|
'deleteAction',
|
||||||
]),
|
]),
|
||||||
columns: grouped[constraintName].map(
|
columns: grouped[constraintName].map(fp.pick(['columnName', 'refColumnName'])),
|
||||||
fp.pick(["columnName", "refColumnName"])
|
|
||||||
)
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @returns {import('@dbgate/types').DbType} */
|
||||||
|
function detectType(col) {
|
||||||
|
switch (col.dataType) {
|
||||||
|
case 'binary':
|
||||||
|
return {
|
||||||
|
typeCode: 'string',
|
||||||
|
isBinary: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
case 'image':
|
||||||
|
return {
|
||||||
|
typeCode: 'string',
|
||||||
|
isBinary: true,
|
||||||
|
isBlob: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
case 'timestamp':
|
||||||
|
return {
|
||||||
|
typeCode: 'string',
|
||||||
|
};
|
||||||
|
case 'varbinary':
|
||||||
|
return {
|
||||||
|
typeCode: 'string',
|
||||||
|
length: col.maxLength,
|
||||||
|
isBinary: true,
|
||||||
|
isVarLength: true,
|
||||||
|
};
|
||||||
|
case 'bit':
|
||||||
|
return {
|
||||||
|
typeCode: 'logical',
|
||||||
|
};
|
||||||
|
|
||||||
|
case 'tinyint':
|
||||||
|
return {
|
||||||
|
typeCode: 'int',
|
||||||
|
bytes: 1,
|
||||||
|
};
|
||||||
|
case 'mediumint':
|
||||||
|
return {
|
||||||
|
typeCode: 'int',
|
||||||
|
bytes: 3,
|
||||||
|
};
|
||||||
|
case 'datetime':
|
||||||
|
return {
|
||||||
|
typeCode: 'datetime',
|
||||||
|
subType: 'datetime',
|
||||||
|
};
|
||||||
|
case 'time':
|
||||||
|
return {
|
||||||
|
typeCode: 'datetime',
|
||||||
|
subType: 'time',
|
||||||
|
};
|
||||||
|
case 'year':
|
||||||
|
return {
|
||||||
|
typeCode: 'datetime',
|
||||||
|
subType: 'year',
|
||||||
|
};
|
||||||
|
case 'date':
|
||||||
|
return {
|
||||||
|
typeCode: 'datetime',
|
||||||
|
subType: 'date',
|
||||||
|
};
|
||||||
|
case 'decimal':
|
||||||
|
case 'numeric':
|
||||||
|
return {
|
||||||
|
typeCode: 'numeric',
|
||||||
|
precision: col.precision,
|
||||||
|
scale: col.scale,
|
||||||
|
};
|
||||||
|
case 'float':
|
||||||
|
return { typeCode: 'float' };
|
||||||
|
case 'uniqueidentifier':
|
||||||
|
return { typeCode: 'string' };
|
||||||
|
case 'smallint':
|
||||||
|
return {
|
||||||
|
typeCode: 'int',
|
||||||
|
bytes: 2,
|
||||||
|
};
|
||||||
|
case 'int':
|
||||||
|
return {
|
||||||
|
typeCode: 'int',
|
||||||
|
bytes: 4,
|
||||||
|
};
|
||||||
|
case 'bigint':
|
||||||
|
return {
|
||||||
|
typeCode: 'int',
|
||||||
|
bytes: 8,
|
||||||
|
};
|
||||||
|
case 'real':
|
||||||
|
return { typeCode: 'float' };
|
||||||
|
case 'char':
|
||||||
|
return {
|
||||||
|
typeCode: 'string',
|
||||||
|
length: col.maxLength,
|
||||||
|
};
|
||||||
|
case 'nchar':
|
||||||
|
return { typeCode: 'string', length: col.maxLength, isUnicode: true };
|
||||||
|
case 'varchar':
|
||||||
|
return {
|
||||||
|
typeCode: 'string',
|
||||||
|
length: col.maxLength,
|
||||||
|
isVarLength: true,
|
||||||
|
};
|
||||||
|
case 'nvarchar':
|
||||||
|
return {
|
||||||
|
typeCode: 'string',
|
||||||
|
length: col.maxLength,
|
||||||
|
isVarLength: true,
|
||||||
|
isUnicode: true,
|
||||||
|
};
|
||||||
|
case 'text':
|
||||||
|
return {
|
||||||
|
typeCode: 'blob',
|
||||||
|
isText: true,
|
||||||
|
};
|
||||||
|
case 'ntext':
|
||||||
|
return {
|
||||||
|
typeCode: 'blob',
|
||||||
|
isText: true,
|
||||||
|
isUnicode: true,
|
||||||
|
};
|
||||||
|
case 'xml':
|
||||||
|
return {
|
||||||
|
typeCode: 'blob',
|
||||||
|
isXml: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
typeCode: 'generic',
|
||||||
|
sql: col.dataType,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
class MsSqlAnalyser extends DatabaseAnalayser {
|
class MsSqlAnalyser extends DatabaseAnalayser {
|
||||||
constructor(pool, driver) {
|
constructor(pool, driver) {
|
||||||
super(pool, driver);
|
super(pool, driver);
|
||||||
@@ -61,26 +185,14 @@ class MsSqlAnalyser extends DatabaseAnalayser {
|
|||||||
triggers = false
|
triggers = false
|
||||||
) {
|
) {
|
||||||
let res = await loadQuery(this.pool, resFileName);
|
let res = await loadQuery(this.pool, resFileName);
|
||||||
res = res.replace("=[OBJECT_ID_CONDITION]", " is not null");
|
res = res.replace('=[OBJECT_ID_CONDITION]', ' is not null');
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
async runAnalysis() {
|
async runAnalysis() {
|
||||||
const tables = await this.driver.query(
|
const tables = await this.driver.query(this.pool, await this.createQuery('tables.sql'));
|
||||||
this.pool,
|
const columns = await this.driver.query(this.pool, await this.createQuery('columns.sql'));
|
||||||
await this.createQuery("tables.sql")
|
const pkColumns = await this.driver.query(this.pool, await this.createQuery('primary_keys.sql'));
|
||||||
);
|
const fkColumns = await this.driver.query(this.pool, await this.createQuery('foreign_keys.sql'));
|
||||||
const columns = await this.driver.query(
|
|
||||||
this.pool,
|
|
||||||
await this.createQuery("columns.sql")
|
|
||||||
);
|
|
||||||
const pkColumns = await this.driver.query(
|
|
||||||
this.pool,
|
|
||||||
await this.createQuery("primary_keys.sql")
|
|
||||||
);
|
|
||||||
const fkColumns = await this.driver.query(
|
|
||||||
this.pool,
|
|
||||||
await this.createQuery("foreign_keys.sql")
|
|
||||||
);
|
|
||||||
|
|
||||||
this.result.tables = tables.rows.map(table => ({
|
this.result.tables = tables.rows.map(table => ({
|
||||||
...table,
|
...table,
|
||||||
@@ -89,10 +201,11 @@ class MsSqlAnalyser extends DatabaseAnalayser {
|
|||||||
.map(({ isNullable, isIdentity, ...col }) => ({
|
.map(({ isNullable, isIdentity, ...col }) => ({
|
||||||
...col,
|
...col,
|
||||||
notNull: !isNullable,
|
notNull: !isNullable,
|
||||||
autoIncrement: !!isIdentity
|
autoIncrement: !!isIdentity,
|
||||||
|
commonType: detectType(col),
|
||||||
})),
|
})),
|
||||||
primaryKey: extractPrimaryKeys(table, pkColumns.rows),
|
primaryKey: extractPrimaryKeys(table, pkColumns.rows),
|
||||||
foreignKeys: extractForeignKeys(table, fkColumns.rows)
|
foreignKeys: extractForeignKeys(table, fkColumns.rows),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
"@dbgate/types": "^0.1.0",
|
"@dbgate/types": "^0.1.0",
|
||||||
"@types/jest": "^25.1.4",
|
"@types/jest": "^25.1.4",
|
||||||
"@types/node": "^13.7.0",
|
"@types/node": "^13.7.0",
|
||||||
"jest": "^25.1.0",
|
"jest": "^24.9.0",
|
||||||
"ts-jest": "^25.2.1",
|
"ts-jest": "^25.2.1",
|
||||||
"typescript": "^3.7.5"
|
"typescript": "^3.7.5"
|
||||||
},
|
},
|
||||||
|
|||||||
19
packages/filterparser/src/getFilterType.ts
Normal file
19
packages/filterparser/src/getFilterType.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { DbTypeCode } from '@dbgate/types';
|
||||||
|
import { FilterType } from './types';
|
||||||
|
|
||||||
|
export function getFilterType(typeCode?: DbTypeCode): FilterType {
|
||||||
|
if (!typeCode) return 'string';
|
||||||
|
switch (typeCode) {
|
||||||
|
case 'int':
|
||||||
|
case 'numeric':
|
||||||
|
case 'float':
|
||||||
|
return 'number';
|
||||||
|
case 'string':
|
||||||
|
return 'string';
|
||||||
|
case 'datetime':
|
||||||
|
return 'datetime';
|
||||||
|
case 'logical':
|
||||||
|
return 'logical';
|
||||||
|
}
|
||||||
|
return 'string';
|
||||||
|
}
|
||||||
2
packages/filterparser/src/index.ts
Normal file
2
packages/filterparser/src/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './parseFilter';
|
||||||
|
export * from './getFilterType';
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import P from 'parsimmon';
|
import P from 'parsimmon';
|
||||||
import { FilterType } from './types';
|
import { FilterType } from './types';
|
||||||
|
import { Condition } from '@dbgate/sqltree';
|
||||||
|
|
||||||
const whitespace = P.regexp(/\s*/m);
|
const whitespace = P.regexp(/\s*/m);
|
||||||
|
|
||||||
@@ -214,7 +215,7 @@ const parsers = {
|
|||||||
logical: createParser('logical'),
|
logical: createParser('logical'),
|
||||||
};
|
};
|
||||||
|
|
||||||
export function parseFilter(value: string, filterType: FilterType) {
|
export function parseFilter(value: string, filterType: FilterType): Condition {
|
||||||
const ast = parsers[filterType].list.tryParse(value);
|
const ast = parsers[filterType].list.tryParse(value);
|
||||||
return ast;
|
return ast;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { SqlDumper } from '@dbgate/types';
|
|||||||
import { Command, Select } from './types';
|
import { Command, Select } from './types';
|
||||||
import { dumpSqlExpression } from './dumpSqlExpression';
|
import { dumpSqlExpression } from './dumpSqlExpression';
|
||||||
import { dumpSqlFromDefinition } from './dumpSqlSource';
|
import { dumpSqlFromDefinition } from './dumpSqlSource';
|
||||||
|
import { dumpSqlCondition } from './dumpSqlCondition';
|
||||||
|
|
||||||
export function dumpSqlSelect(dmp: SqlDumper, select: Select) {
|
export function dumpSqlSelect(dmp: SqlDumper, select: Select) {
|
||||||
dmp.put('^select ');
|
dmp.put('^select ');
|
||||||
@@ -25,8 +26,13 @@ export function dumpSqlSelect(dmp: SqlDumper, select: Select) {
|
|||||||
}
|
}
|
||||||
dmp.put('^from ');
|
dmp.put('^from ');
|
||||||
dumpSqlFromDefinition(dmp, select.from);
|
dumpSqlFromDefinition(dmp, select.from);
|
||||||
|
if (select.where) {
|
||||||
|
dmp.put('&n^where');
|
||||||
|
dumpSqlCondition(dmp, select.where);
|
||||||
|
dmp.put('&n');
|
||||||
|
}
|
||||||
if (select.groupBy) {
|
if (select.groupBy) {
|
||||||
dmp.put('&ngroup ^by ');
|
dmp.put('&n^group ^by ');
|
||||||
dmp.putCollection(', ', select.groupBy, expr => dumpSqlExpression(dmp, expr));
|
dmp.putCollection(', ', select.groupBy, expr => dumpSqlExpression(dmp, expr));
|
||||||
dmp.put('&n');
|
dmp.put('&n');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export interface Select {
|
|||||||
selectAll?: boolean;
|
selectAll?: boolean;
|
||||||
orderBy?: OrderByExpression[];
|
orderBy?: OrderByExpression[];
|
||||||
groupBy?: Expression[];
|
groupBy?: Expression[];
|
||||||
|
where?: Condition;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Command = Select;
|
export type Command = Select;
|
||||||
|
|||||||
3
packages/types/dbinfo.d.ts
vendored
3
packages/types/dbinfo.d.ts
vendored
@@ -1,3 +1,5 @@
|
|||||||
|
import { DbType } from './DbType';
|
||||||
|
|
||||||
export interface NamedObjectInfo {
|
export interface NamedObjectInfo {
|
||||||
pureName: string;
|
pureName: string;
|
||||||
schemaName: string;
|
schemaName: string;
|
||||||
@@ -39,6 +41,7 @@ export interface ColumnInfo {
|
|||||||
isSparse: boolean;
|
isSparse: boolean;
|
||||||
defaultValue: string;
|
defaultValue: string;
|
||||||
defaultConstraint: string;
|
defaultConstraint: string;
|
||||||
|
commonType?: DbType;
|
||||||
}
|
}
|
||||||
export interface TableInfo extends NamedObjectInfo {
|
export interface TableInfo extends NamedObjectInfo {
|
||||||
columns: ColumnInfo[];
|
columns: ColumnInfo[];
|
||||||
|
|||||||
66
packages/types/dbtypes.d.ts
vendored
Normal file
66
packages/types/dbtypes.d.ts
vendored
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
export type DbSizeType = 'small' | 'medium' | 'tiny' | 'long';
|
||||||
|
|
||||||
|
export interface DbTypeDatetime {
|
||||||
|
typeCode: 'datetime';
|
||||||
|
subType?: 'date' | 'datetime' | 'time' | 'year' | 'interval';
|
||||||
|
extendedPrecision?: boolean;
|
||||||
|
hasTimeZone?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DbTypeBlob {
|
||||||
|
typeCode: 'blob';
|
||||||
|
size?: DbSizeType;
|
||||||
|
isText?: boolean;
|
||||||
|
isUnicode?: boolean;
|
||||||
|
isXml?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DbTypeFloat {
|
||||||
|
typeCode: 'float';
|
||||||
|
bytes?: number;
|
||||||
|
isMoney?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DbTypeGeneric {
|
||||||
|
typeCode: 'generic';
|
||||||
|
sql: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DbTypeLogical {
|
||||||
|
typeCode: 'logical';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DbTypeNumeric {
|
||||||
|
typeCode: 'numeric';
|
||||||
|
precision?: number;
|
||||||
|
scale?: number;
|
||||||
|
autoIncrement?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DbTypeString {
|
||||||
|
typeCode: 'string';
|
||||||
|
length?: number;
|
||||||
|
isUnicode?: boolean;
|
||||||
|
isBinary?: boolean;
|
||||||
|
isBit?: boolean;
|
||||||
|
isVarLength?: boolean;
|
||||||
|
isBlob?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DbTypeInt {
|
||||||
|
typeCode: 'int';
|
||||||
|
bytes?: number;
|
||||||
|
autoIncrement?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DbType =
|
||||||
|
| DbTypeDatetime
|
||||||
|
| DbTypeBlob
|
||||||
|
| DbTypeFloat
|
||||||
|
| DbTypeGeneric
|
||||||
|
| DbTypeLogical
|
||||||
|
| DbTypeNumeric
|
||||||
|
| DbTypeString
|
||||||
|
| DbTypeInt;
|
||||||
|
|
||||||
|
export type DbTypeCode = DbType['typeCode'];
|
||||||
1
packages/types/index.d.ts
vendored
1
packages/types/index.d.ts
vendored
@@ -21,3 +21,4 @@ export * from "./dbinfo";
|
|||||||
export * from "./query";
|
export * from "./query";
|
||||||
export * from "./dialect";
|
export * from "./dialect";
|
||||||
export * from "./dumper";
|
export * from "./dumper";
|
||||||
|
export * from "./dbtypes";
|
||||||
|
|||||||
@@ -185,6 +185,10 @@ export default function DataFilterControl({ isReadOnly = false, filterType, filt
|
|||||||
// }
|
// }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
editorRef.current.value = filter || '';
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleShowMenu = () => {
|
const handleShowMenu = () => {
|
||||||
const rect = buttonRef.current.getBoundingClientRect();
|
const rect = buttonRef.current.getBoundingClientRect();
|
||||||
showMenu(
|
showMenu(
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import moment from 'moment';
|
||||||
|
import _ from 'lodash';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import useFetch from '../utility/useFetch';
|
import useFetch from '../utility/useFetch';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
@@ -8,6 +10,7 @@ import { SeriesSizes } from './SeriesSizes';
|
|||||||
import axios from '../utility/axios';
|
import axios from '../utility/axios';
|
||||||
import ColumnLabel from './ColumnLabel';
|
import ColumnLabel from './ColumnLabel';
|
||||||
import DataFilterControl from './DataFilterControl';
|
import DataFilterControl from './DataFilterControl';
|
||||||
|
import { getFilterType } from '@dbgate/filterparser';
|
||||||
|
|
||||||
const GridContainer = styled.div`
|
const GridContainer = styled.div`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -75,6 +78,16 @@ const HintSpan = styled.span`
|
|||||||
color: gray;
|
color: gray;
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
`;
|
`;
|
||||||
|
const NullSpan = styled.span`
|
||||||
|
color: gray;
|
||||||
|
font-style: italic;
|
||||||
|
`;
|
||||||
|
|
||||||
|
function CellFormattedValue({ value }) {
|
||||||
|
if (value == null) return <NullSpan>(NULL)</NullSpan>;
|
||||||
|
if (_.isDate(value)) return moment(value).format('YYYY-MM-DD HH:mm:ss');
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
/** @param props {import('./types').DataGridProps} */
|
/** @param props {import('./types').DataGridProps} */
|
||||||
export default function DataGridCore(props) {
|
export default function DataGridCore(props) {
|
||||||
@@ -300,7 +313,6 @@ export default function DataGridCore(props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// console.log('visibleRealColumnIndexes', visibleRealColumnIndexes);
|
// console.log('visibleRealColumnIndexes', visibleRealColumnIndexes);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GridContainer ref={containerRef}>
|
<GridContainer ref={containerRef}>
|
||||||
<Table>
|
<Table>
|
||||||
@@ -322,7 +334,7 @@ export default function DataGridCore(props) {
|
|||||||
style={{ width: col.widthPx, minWidth: col.widthPx, maxWidth: col.widthPx }}
|
style={{ width: col.widthPx, minWidth: col.widthPx, maxWidth: col.widthPx }}
|
||||||
>
|
>
|
||||||
<DataFilterControl
|
<DataFilterControl
|
||||||
filterType="string"
|
filterType={getFilterType(col.commonType ? col.commonType.typeCode : null)}
|
||||||
filter={display.getFilter(col.uniqueName)}
|
filter={display.getFilter(col.uniqueName)}
|
||||||
setFilter={value => display.setFilter(col.uniqueName, value)}
|
setFilter={value => display.setFilter(col.uniqueName, value)}
|
||||||
/>
|
/>
|
||||||
@@ -340,7 +352,7 @@ export default function DataGridCore(props) {
|
|||||||
key={col.uniqueName}
|
key={col.uniqueName}
|
||||||
style={{ width: col.widthPx, minWidth: col.widthPx, maxWidth: col.widthPx }}
|
style={{ width: col.widthPx, minWidth: col.widthPx, maxWidth: col.widthPx }}
|
||||||
>
|
>
|
||||||
{row[col.uniqueName]}
|
<CellFormattedValue value={row[col.uniqueName]} />
|
||||||
{col.hintColumnName && <HintSpan>{row[col.hintColumnName]}</HintSpan>}
|
{col.hintColumnName && <HintSpan>{row[col.hintColumnName]}</HintSpan>}
|
||||||
</TableBodyCell>
|
</TableBodyCell>
|
||||||
))}
|
))}
|
||||||
|
|||||||
Reference in New Issue
Block a user