Skip to content

Commit 4fde091

Browse files
authored
Merge pull request #1221 from merico-dev/1220-provide-full-information-when-calling-query-api
1220 provide full information when calling query api
2 parents 6a87aef + a5e4e90 commit 4fde091

File tree

15 files changed

+144
-149
lines changed

15 files changed

+144
-149
lines changed

api/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@devtable/api",
3-
"version": "10.41.0",
3+
"version": "10.42.1",
44
"description": "",
55
"main": "index.js",
66
"scripts": {

dashboard/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@devtable/dashboard",
3-
"version": "10.41.0",
3+
"version": "10.42.1",
44
"license": "Apache-2.0",
55
"publishConfig": {
66
"access": "public",

dashboard/src/api-caller/index.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { DataSourceType, TPayloadForSQL } from '~/model';
22
import { formatSQL, postProcessSQLQuery, preProcessSQLQuery } from '../utils/sql';
3-
import { APIClient } from './request';
3+
import { APIClient, TAdditionalQueryInfo } from './request';
44
import { IDataSource, PaginationResponse } from './types';
55
import { payloadToDashboardState } from '~/utils/dashboard-state';
66
import axios, { AxiosError } from 'axios';
@@ -17,17 +17,18 @@ interface IQueryBySQL {
1717
name: string;
1818
query: { type: DataSourceType; key: string; sql: string; pre_process: string; post_process: string };
1919
payload: TPayloadForSQL;
20+
additionals: TAdditionalQueryInfo;
2021
}
2122

22-
export async function queryBySQL({ query, name, payload }: IQueryBySQL, signal: AbortSignal) {
23+
export async function queryBySQL({ query, name, payload, additionals }: IQueryBySQL, signal: AbortSignal) {
2324
if (!query.sql) {
2425
return [];
2526
}
2627
const { type, key, sql, pre_process, post_process } = query;
2728

2829
const formattedSQL = formatSQL(sql, payload);
2930
const finalSQL = preProcessSQLQuery({ sql: formattedSQL, pre_process });
30-
let data = await APIClient.query(signal)({ type, key, query: finalSQL }, { params: { name } });
31+
let data = await APIClient.query(signal)({ type, key, query: finalSQL, ...additionals }, { params: { name } });
3132
data = postProcessSQLQuery(post_process, data, payloadToDashboardState(payload));
3233
return data;
3334
}
@@ -37,12 +38,13 @@ interface IQueryByHTTP {
3738
key: string;
3839
configString: string;
3940
name: string;
41+
additionals: TAdditionalQueryInfo;
4042
}
4143

42-
export async function queryByHTTP({ type, key, configString, name }: IQueryByHTTP, signal: AbortSignal) {
44+
export async function queryByHTTP({ type, key, configString, name, additionals }: IQueryByHTTP, signal: AbortSignal) {
4345
try {
4446
const ret = await APIClient.httpDataSourceQuery<AnyObject>(signal)(
45-
{ type, key, query: configString },
47+
{ type, key, query: configString, ...additionals },
4648
{ params: { name } },
4749
);
4850
return ret;

dashboard/src/api-caller/request.ts

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,39 @@
1-
import { DataSourceType } from '~/model';
1+
import { AxiosResponse, Method } from 'axios';
2+
import { DataSourceType, TDashboardState } from '~/model';
23
import { AnyObject, IDashboardConfig } from '..';
3-
import { DefaultApiClient, IAPIClient, IAPIClientRequestOptions } from '../shared';
4-
import axios, { AxiosResponse, Method } from 'axios';
4+
import { DefaultApiClient, IAPIClient } from '../shared';
55

6-
export { FacadeApiClient, DefaultApiClient } from '../shared';
6+
export { DefaultApiClient, FacadeApiClient } from '../shared';
77
export type { IAPIClient, IAPIClientRequestOptions } from '../shared';
8+
9+
export type TAdditionalQueryInfo = {
10+
content_id: string;
11+
query_id: string;
12+
params: TDashboardState;
13+
};
814
export type TQueryPayload = {
915
type: DataSourceType;
1016
key: string;
1117
query: string;
1218
env?: AnyObject;
19+
} & TAdditionalQueryInfo;
20+
21+
export type TQueryStructureRequest = {
22+
query_type: 'TABLES' | 'COLUMNS' | 'DATA' | 'INDEXES' | 'COUNT';
23+
type: 'postgresql' | 'mysql';
24+
key: string; // datasource key
25+
table_schema: string;
26+
table_name: string;
27+
limit?: number; // default 20
28+
offset?: number; // default 0
1329
};
1430

1531
export interface IDashboardAPIClient extends IAPIClient {
1632
query: <T = $TSFixMe>(signal?: AbortSignal) => (data: TQueryPayload, options?: AnyObject) => Promise<T>;
1733
httpDataSourceQuery: <T = $TSFixMe>(
1834
signal?: AbortSignal,
1935
) => (data: TQueryPayload, options?: AnyObject) => Promise<AxiosResponse<T>>;
36+
structure: <T = $TSFixMe>(signal?: AbortSignal) => (data: TQueryStructureRequest, options?: AnyObject) => Promise<T>;
2037
}
2138

2239
export class DashboardApiClient extends DefaultApiClient implements IDashboardAPIClient {
@@ -41,6 +58,12 @@ export class DashboardApiClient extends DefaultApiClient implements IDashboardAP
4158
return this.getRequest<AxiosResponse<T>>('POST', signal)('/query', data, options, true);
4259
};
4360
}
61+
62+
structure<T>(signal?: AbortSignal): (data: TQueryStructureRequest, options?: AnyObject) => Promise<T> {
63+
return async (data: TQueryStructureRequest, options: AnyObject = {}) => {
64+
return this.post<T>(signal)('/query/structure', data, options);
65+
};
66+
}
4467
}
4568

4669
export class DashboardApiFacadeClient implements IDashboardAPIClient {
@@ -54,6 +77,10 @@ export class DashboardApiFacadeClient implements IDashboardAPIClient {
5477
return this.implementation.httpDataSourceQuery<T>(signal);
5578
}
5679

80+
structure(signal?: AbortSignal) {
81+
return this.implementation.structure(signal);
82+
}
83+
5784
getRequest<T>(method: Method, signal?: AbortSignal) {
5885
return this.implementation.getRequest<T>(method, signal);
5986
}

dashboard/src/dashboard-editor/model/content/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ import {
3131
} from '~/model';
3232
import { PanelModelInstance, PanelsModel } from '../panels';
3333
import { getInitialDashboardViewsModel, ViewsModel } from '../views';
34+
import { payloadToDashboardState } from '~/utils/dashboard-state';
35+
import { TAdditionalQueryInfo } from '~/api-caller/request';
3436

3537
const _ContentModel = types
3638
.model({
@@ -130,6 +132,12 @@ const _ContentModel = types
130132
filters: self.filters.values,
131133
} as TPayloadForViz;
132134
},
135+
get dashboardState() {
136+
return payloadToDashboardState(this.payloadForSQL);
137+
},
138+
getAdditionalQueryInfo(query_id: string): TAdditionalQueryInfo {
139+
return { content_id: self.id, query_id, params: this.dashboardState };
140+
},
133141
get changed() {
134142
return (
135143
this.filtersChanged ||
Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { getParent, types } from 'mobx-state-tree';
2-
import { DataSourceType } from '~/model';
1+
import { types } from 'mobx-state-tree';
32

43
export type ColumnInfoType = {
54
column_key: string;
@@ -25,39 +24,4 @@ export const ColumnsModel = types
2524
get empty() {
2625
return self.data.length === 0;
2726
},
28-
get sql() {
29-
const payload: { type: DataSourceType; table_name: string; table_schema: string } = getParent(self, 1);
30-
const { type, table_name, table_schema } = payload;
31-
32-
if (type === DataSourceType.MySQL) {
33-
return `
34-
SELECT ordinal_position, column_key, column_name, column_type, is_nullable, column_default, column_comment
35-
FROM information_schema.columns
36-
WHERE table_name = '${table_name}' AND table_schema = '${table_schema}'
37-
`;
38-
}
39-
if (type === DataSourceType.Postgresql) {
40-
const attrelid = `'${table_schema}.${table_name}'::regclass`;
41-
return `
42-
SELECT
43-
ordinal_position,
44-
UPPER(pc.contype) AS column_key,
45-
pg_get_constraintdef(pc.oid) AS column_key_text,
46-
column_name,
47-
format_type(atttypid, atttypmod) AS column_type,
48-
is_nullable,
49-
column_default,
50-
pg_catalog.col_description(${attrelid}, ordinal_position) AS column_comment
51-
FROM
52-
information_schema.columns
53-
JOIN pg_attribute pa ON pa.attrelid = ${attrelid}
54-
AND attname = column_name
55-
LEFT JOIN pg_constraint pc ON pc.conrelid = ${attrelid} AND ordinal_position = any(pc.conkey)
56-
WHERE
57-
table_name = '${table_name}' AND table_schema = '${table_schema}';
58-
`;
59-
}
60-
61-
return '';
62-
},
6327
}));

dashboard/src/dashboard-editor/model/datasources/datasource.ts

Lines changed: 72 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ import _ from 'lodash';
33
import { reaction } from 'mobx';
44
import { addDisposer, flow, Instance, toGenerator, types } from 'mobx-state-tree';
55
import { QueryFailureError } from '~/api-caller';
6-
import { APIClient } from '~/api-caller/request';
6+
import { APIClient, TQueryStructureRequest } from '~/api-caller/request';
77
import { DataSourceMetaModel } from '~/model/meta-model/datasources';
8-
import { ColumnsModel } from './columns';
9-
import { IndexesModel } from './indexes';
8+
import { AnyObject } from '~/types';
9+
import { ColumnInfoType, ColumnsModel } from './columns';
10+
import { IndexesModel, IndexInfoType } from './indexes';
1011
import { TableDataModel } from './table-data';
1112
import { TableInfoType, TablesModel } from './tables';
1213

@@ -23,6 +24,15 @@ export const DataSourceModel = types
2324
table_name: types.optional(types.string, ''),
2425
}),
2526
)
27+
.views((self) => ({
28+
get sqlDataSourceType() {
29+
return self.type as TQueryStructureRequest['type'];
30+
},
31+
get reloadConditionString() {
32+
const { type, table_name, table_schema } = self;
33+
return `${type};${table_name};${table_schema}`;
34+
},
35+
}))
2636
.volatile(() => ({
2737
controllers: {
2838
tables: new AbortController(),
@@ -53,10 +63,16 @@ export const DataSourceModel = types
5363
self.controllers.tables = new AbortController();
5464
self.tables.state = 'loading';
5565
try {
56-
const tables: TableInfoType[] = yield* toGenerator(
57-
APIClient.query(self.controllers.tables.signal)(
58-
{ type: self.type, key: self.key, query: self.tables.sql },
59-
{},
66+
const tables = yield* toGenerator(
67+
APIClient.structure<TableInfoType[]>(self.controllers.tables.signal)(
68+
{
69+
query_type: 'TABLES',
70+
type: self.sqlDataSourceType,
71+
key: self.key,
72+
table_schema: '',
73+
table_name: '',
74+
},
75+
{ params: { query_type: 'TABLES' } },
6076
),
6177
);
6278
self.tables.data = _.groupBy(tables, 'table_schema');
@@ -87,9 +103,15 @@ export const DataSourceModel = types
87103
self.columns.state = 'loading';
88104
try {
89105
self.columns.data = yield* toGenerator(
90-
APIClient.query(self.controllers.columns.signal)(
91-
{ type: self.type, key: self.key, query: self.columns.sql },
92-
{},
106+
APIClient.structure<ColumnInfoType[]>(self.controllers.columns.signal)(
107+
{
108+
query_type: 'COLUMNS',
109+
type: self.sqlDataSourceType,
110+
key: self.key,
111+
table_schema: self.table_schema,
112+
table_name: self.table_name,
113+
},
114+
{ params: { query_type: 'COLUMNS' } },
93115
),
94116
);
95117
self.columns.state = 'idle';
@@ -112,9 +134,15 @@ export const DataSourceModel = types
112134
self.indexes.state = 'loading';
113135
try {
114136
self.indexes.data = yield* toGenerator(
115-
APIClient.query(self.controllers.indexes.signal)(
116-
{ type: self.type, key: self.key, query: self.indexes.sql },
117-
{},
137+
APIClient.structure<IndexInfoType[]>(self.controllers.indexes.signal)(
138+
{
139+
query_type: 'INDEXES',
140+
type: self.sqlDataSourceType,
141+
key: self.key,
142+
table_schema: self.table_schema,
143+
table_name: self.table_name,
144+
},
145+
{ params: { query_type: 'INDEXES' } },
118146
),
119147
);
120148
self.indexes.state = 'idle';
@@ -138,12 +166,29 @@ export const DataSourceModel = types
138166
m.state = 'loading';
139167
try {
140168
m.data = yield* toGenerator(
141-
APIClient.query(self.controllers.tableData.signal)({ type: self.type, key: self.key, query: m.sql }, {}),
169+
APIClient.structure<AnyObject[]>(self.controllers.tableData.signal)(
170+
{
171+
query_type: 'DATA',
172+
type: self.sqlDataSourceType,
173+
key: self.key,
174+
table_schema: self.table_schema,
175+
table_name: self.table_name,
176+
limit: m.limit,
177+
offset: m.offset,
178+
},
179+
{ params: { query_type: 'DATA' } },
180+
),
142181
);
143182
const [{ total }] = yield* toGenerator(
144-
APIClient.query(self.controllers.tableData.signal)(
145-
{ type: self.type, key: self.key, query: m.countSql },
146-
{},
183+
APIClient.structure(self.controllers.tableData.signal)(
184+
{
185+
query_type: 'COUNT',
186+
type: self.sqlDataSourceType,
187+
key: self.key,
188+
table_schema: self.table_schema,
189+
table_name: self.table_name,
190+
},
191+
{ params: { query_type: 'COUNT' } },
147192
),
148193
);
149194
m.total = Number(total);
@@ -167,7 +212,7 @@ export const DataSourceModel = types
167212
afterCreate() {
168213
addDisposer(
169214
self,
170-
reaction(() => self.columns.sql, self.loadColumns, {
215+
reaction(() => self.reloadConditionString, self.loadColumns, {
171216
fireImmediately: false,
172217
delay: 500,
173218
}),
@@ -178,17 +223,21 @@ export const DataSourceModel = types
178223
afterCreate() {
179224
addDisposer(
180225
self,
181-
reaction(() => self.indexes.sql, self.loadIndexes, {
226+
reaction(() => self.reloadConditionString, self.loadIndexes, {
182227
fireImmediately: false,
183228
delay: 500,
184229
}),
185230
);
186231
addDisposer(
187232
self,
188-
reaction(() => self.tableData.sql, self.loadTableData, {
189-
fireImmediately: false,
190-
delay: 0,
191-
}),
233+
reaction(
234+
() => `${self.reloadConditionString};limit:${self.tableData.limit};offset:${self.tableData.offset}`,
235+
self.loadTableData,
236+
{
237+
fireImmediately: false,
238+
delay: 0,
239+
},
240+
),
192241
);
193242
},
194243
}));

0 commit comments

Comments
 (0)