Skip to content

Commit 10c17e2

Browse files
authored
Merge pull request #1457 from lowcoder-org/feat/alasql
Feat/alasql
2 parents c3068a6 + 3a4ab7c commit 10c17e2

File tree

14 files changed

+231
-3
lines changed

14 files changed

+231
-3
lines changed

client/packages/lowcoder/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"@types/react-signature-canvas": "^1.0.2",
3737
"@types/react-test-renderer": "^18.0.0",
3838
"@types/react-virtualized": "^9.21.21",
39+
"alasql": "^4.6.2",
3940
"animate.css": "^4.1.1",
4041
"antd": "^5.20.0",
4142
"axios": "^1.7.7",

client/packages/lowcoder/src/components/ResCreatePanel.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,13 @@ const ResButton = (props: {
169169
compType: "streamApi",
170170
},
171171
},
172+
alasql: {
173+
label: trans("query.quickAlasql"),
174+
type: BottomResTypeEnum.Query,
175+
extra: {
176+
compType: "alasql",
177+
},
178+
},
172179
graphql: {
173180
label: trans("query.quickGraphql"),
174181
type: BottomResTypeEnum.Query,
@@ -319,6 +326,7 @@ export function ResCreatePanel(props: ResCreateModalProps) {
319326
<DataSourceListWrapper $placement={placement}>
320327
<ResButton size={buttonSize} identifier={"restApi"} onSelect={onSelect} />
321328
<ResButton size={buttonSize} identifier={"streamApi"} onSelect={onSelect} />
329+
<ResButton size={buttonSize} identifier={"alasql"} onSelect={onSelect} />
322330
<ResButton size={buttonSize} identifier={"graphql"} onSelect={onSelect} />
323331
{datasource.map((i) => (
324332
<ResButton size={buttonSize} key={i.id} identifier={i} onSelect={onSelect} />
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import { QueryConfigItemWrapper, QueryConfigLabel, QueryConfigWrapper } from "components/query";
2+
import { simpleMultiComp } from "comps/generators/multi";
3+
import { JSONValue } from "../../../util/jsonTypes";
4+
import { ParamsStringControl } from "../../controls/paramsControl";
5+
import { dropdownControl } from "@lowcoder-ee/comps/controls/dropdownControl";
6+
import { QueryResult } from "../queryComp";
7+
import { QUERY_EXECUTION_ERROR, QUERY_EXECUTION_OK } from "@lowcoder-ee/constants/queryConstants";
8+
import { getDynamicStringSegments, isDynamicSegment } from "lowcoder-core";
9+
import alasql from "alasql";
10+
import { trans } from "i18n";
11+
12+
const childrenMap = {
13+
databaseType: dropdownControl(
14+
[
15+
{ label: "Data Query", value: "dataQuery" },
16+
{ label: "Local Database", value: "localDB" },
17+
] as const,
18+
"dataQuery"
19+
),
20+
database: dropdownControl(
21+
[
22+
{ label: "Local Storage", value: "LOCALSTORAGE" },
23+
{ label: "IndexedDB", value: "INDEXEDDB" },
24+
] as const,
25+
"LOCALSTORAGE"
26+
),
27+
sql: ParamsStringControl,
28+
};
29+
30+
const AlaSqlTmpQuery = simpleMultiComp(childrenMap);
31+
32+
// TODO: Support multiple queries
33+
export class AlaSqlQuery extends AlaSqlTmpQuery {
34+
override getView() {
35+
const children = this.children;
36+
const params = [ ...children.sql.getQueryParams() ];
37+
const databaseType = children.databaseType.getView();
38+
const selectedDB = children.database.getView();
39+
const paramsMap: Record<string, any> = {};
40+
params.forEach(({key, value}) => {
41+
paramsMap[key] = value();
42+
});
43+
44+
const sqlQuery = children.sql.children.text.unevaledValue.replace(/ +/g, ' ');
45+
const isCreateDBQuery = sqlQuery.toUpperCase().startsWith('CREATE DATABASE');
46+
47+
return async (p: { args?: Record<string, unknown> }): Promise<QueryResult> => {
48+
try {
49+
let result: JSONValue;
50+
const timer = performance.now();
51+
52+
if (databaseType === 'localDB' && isCreateDBQuery) {
53+
const updatedQuery = `${sqlQuery.slice(0, 6)} ${selectedDB} ${sqlQuery.slice(6)}`;
54+
const tableName = updatedQuery.split(' ').pop()?.replace(';', '');
55+
result = alasql(updatedQuery);
56+
result = alasql(`ATTACH ${selectedDB} DATABASE ${tableName};`);
57+
} else {
58+
let segments = getDynamicStringSegments(sqlQuery);
59+
let dataArr: any = [];
60+
segments = segments.map((segment) => {
61+
if (isDynamicSegment(segment)) {
62+
const key = segment.replace('{{','').replace('}}','');
63+
dataArr.push(paramsMap[key]);
64+
return '?';
65+
}
66+
return segment;
67+
})
68+
result = alasql(segments.join(' '), dataArr);
69+
}
70+
71+
return {
72+
data: result as JSONValue,
73+
code: QUERY_EXECUTION_OK,
74+
success: true,
75+
runTime: Number((performance.now() - timer).toFixed()),
76+
};
77+
} catch (e) {
78+
return {
79+
success: false,
80+
data: "",
81+
code: QUERY_EXECUTION_ERROR,
82+
message: (e as any).message || "",
83+
};
84+
}
85+
};
86+
}
87+
88+
propertyView(props: { datasourceId: string }) {
89+
return <PropertyView {...props} comp={this} />;
90+
}
91+
}
92+
93+
const PropertyView = (props: { comp: InstanceType<typeof AlaSqlQuery>; datasourceId: string }) => {
94+
const { comp } = props;
95+
const { children } = comp;
96+
97+
return (
98+
<>
99+
<QueryConfigWrapper>
100+
<QueryConfigLabel>{trans("query.databaseType")}</QueryConfigLabel>
101+
<QueryConfigItemWrapper>
102+
{children.databaseType.propertyView({
103+
styleName: "medium",
104+
width: "100%",
105+
})}
106+
</QueryConfigItemWrapper>
107+
</QueryConfigWrapper>
108+
109+
{children.databaseType.getView() === 'localDB' && (
110+
<QueryConfigWrapper>
111+
<QueryConfigLabel>{trans("query.chooseDatabase")}</QueryConfigLabel>
112+
<QueryConfigItemWrapper>
113+
{children.database.propertyView({
114+
styleName: "medium",
115+
width: "100%",
116+
})}
117+
</QueryConfigItemWrapper>
118+
</QueryConfigWrapper>
119+
)}
120+
121+
<QueryConfigWrapper>
122+
<QueryConfigItemWrapper>
123+
{children.sql.propertyView({
124+
placement: "bottom",
125+
placeholder: "SELECT * FROM users WHERE user_id = {{userId}}::uuid",
126+
styleName: "medium",
127+
language: "sql",
128+
enableMetaCompletion: true,
129+
})}
130+
</QueryConfigItemWrapper>
131+
</QueryConfigWrapper>
132+
</>
133+
);
134+
};

client/packages/lowcoder/src/comps/queries/queryComp/queryPropertyView.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,7 @@ function useDatasourceStatus(datasourceId: string, datasourceType: ResourceType)
734734
datasourceType === "js" ||
735735
datasourceType === "streamApi" ||
736736
datasourceType === "libraryQuery" ||
737+
datasourceType === "alasql" ||
737738
datasourceId === QUICK_REST_API_ID ||
738739
datasourceId === QUICK_GRAPHQL_ID
739740
) {

client/packages/lowcoder/src/comps/queries/resourceDropdown.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ const QuickGraphqlValue: ResourceOptionValue = {
102102
type: "graphql",
103103
};
104104

105+
const QuickAlasqlValue: ResourceOptionValue = {
106+
id: "",
107+
type: "alasql",
108+
};
109+
105110
interface ResourceDropdownProps {
106111
changeResource: (datasourceId: string, value: string) => void;
107112
selectedResource: ResourceOptionValue;
@@ -265,6 +270,17 @@ export const ResourceDropdown = (props: ResourceDropdownProps) => {
265270
<SelectOptionLabel>{trans("query.quickStreamAPI")} </SelectOptionLabel>
266271
</SelectOptionContains>
267272
</SelectOption>
273+
274+
<SelectOption
275+
key={JSON.stringify(QuickAlasqlValue)}
276+
label={trans("query.quickAlasql")}
277+
value={JSON.stringify(QuickAlasqlValue)}
278+
>
279+
<SelectOptionContains>
280+
{getBottomResIcon("restApi")}
281+
<SelectOptionLabel>{trans("query.quickAlasql")} </SelectOptionLabel>
282+
</SelectOptionContains>
283+
</SelectOption>
268284

269285
<SelectOption
270286
key={JSON.stringify(QuickGraphqlValue)}

client/packages/lowcoder/src/comps/queries/sqlQuery/SQLQuery.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ export const NOT_SUPPORT_GUI_SQL_QUERY: string[] = [
255255
"snowflake",
256256
"tdengine",
257257
"dameng",
258+
"alasql",
258259
];
259260
const SUPPORT_UPSERT_SQL_QUERY: string[] = [
260261
"mysql",

client/packages/lowcoder/src/constants/datasourceConstants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const databasePlugins: Partial<DatasourceType>[] = [
1515
"clickHouse",
1616
"snowflake",
1717
"mariadb",
18+
"alasql",
1819
];
1920

2021
export const apiPluginsForQueryLibrary: Partial<DatasourceType>[] = [
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export const libNames = new Set(["uuid", "numbro", "Papa", "supabase"]);
1+
export const libNames = new Set(["uuid", "numbro", "Papa", "supabase", "alasql"]);

client/packages/lowcoder/src/constants/queryConstants.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { GraphqlQuery } from "../comps/queries/httpQuery/graphqlQuery";
1313
import { toPluginQuery } from "comps/queries/pluginQuery/pluginQuery";
1414
import { MultiCompConstructor } from "lowcoder-core";
1515
import { DataSourcePluginMeta } from "lowcoder-sdk/dataSource";
16+
import { AlaSqlQuery } from "@lowcoder-ee/comps/queries/httpQuery/alasqlQuery";
1617

1718
export type DatasourceType =
1819
| "mysql"
@@ -29,13 +30,15 @@ export type DatasourceType =
2930
| "googleSheets"
3031
| "graphql"
3132
| "snowflake"
32-
| "mariadb";
33+
| "mariadb"
34+
| "alasql";
3335

3436
export type ResourceType = DatasourceType | "js" | "libraryQuery" | "view";
3537

3638
export const QueryMap = {
3739
js: JSQuery,
3840
mysql: SQLQuery,
41+
alasql: AlaSqlQuery,
3942
restApi: HttpQuery,
4043
streamApi: StreamQuery,
4144
mongodb: MongoQuery,

client/packages/lowcoder/src/global.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ declare global {
99
numbro: any;
1010
Papa: any;
1111
uuid: any;
12+
alasql: any;
1213
}
1314
}

client/packages/lowcoder/src/i18n/locales/en.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,9 @@ export const en = {
731731
"quickRestAPI": "REST Query",
732732
"quickStreamAPI": "Stream Query",
733733
"quickGraphql": "GraphQL Query",
734+
"quickAlasql": "Local SQL Query",
735+
"databaseType": "Database Type",
736+
"chooseDatabase": "Choose Database",
734737
"lowcoderAPI": "Lowcoder API",
735738
"executeJSCode": "Run JavaScript Code",
736739
"importFromQueryLibrary": "Import from Query Library",

client/packages/lowcoder/src/index.sdk.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import numbro from "numbro";
22
import Papa from "papaparse";
33
import * as uuid from "uuid";
44
import * as supabase from "@supabase/supabase-js";
5+
import * as alasql from "alasql";
56

67
import * as styledNameExports from "styled-components";
78
import styledDefault from "styled-components";
@@ -136,3 +137,4 @@ window.numbro = numbro;
136137
window.Papa = Papa;
137138
window.uuid = uuid;
138139
window.supabase = supabase;
140+
window.alasql = alasql;

client/packages/lowcoder/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import ResizeObserver from "resize-observer-polyfill";
33
import numbro from "numbro";
44
import Papa from "papaparse";
55
import * as supabase from "@supabase/supabase-js";
6+
import * as alasql from "alasql";
67

78
import * as uuid from "uuid";
89
import "regenerator-runtime/runtime";
@@ -18,6 +19,7 @@ window.numbro = numbro;
1819
window.Papa = Papa;
1920
window.uuid = uuid;
2021
window.supabase = supabase;
22+
window.alasql = alasql;
2123

2224
// for chrome 63
2325
if (!window.ResizeObserver) {

client/yarn.lock

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5932,6 +5932,18 @@ __metadata:
59325932
languageName: node
59335933
linkType: hard
59345934

5935+
"alasql@npm:^4.6.2":
5936+
version: 4.6.2
5937+
resolution: "alasql@npm:4.6.2"
5938+
dependencies:
5939+
cross-fetch: 4.1.0
5940+
yargs: 16
5941+
bin:
5942+
alasql: bin/alasql-cli.js
5943+
checksum: cc68e87eeaa72ddaec5f20c4ca631e2a8ddb45e38d4b7de41cb14661ead657b1afec8d9530160f66fe5253e9724db9ada5fc63ba2c5bcacf5b8f9583c7b0870f
5944+
languageName: node
5945+
linkType: hard
5946+
59355947
"animate.css@npm:^4.1.1":
59365948
version: 4.1.1
59375949
resolution: "animate.css@npm:4.1.1"
@@ -7309,6 +7321,17 @@ __metadata:
73097321
languageName: node
73107322
linkType: hard
73117323

7324+
"cliui@npm:^7.0.2":
7325+
version: 7.0.4
7326+
resolution: "cliui@npm:7.0.4"
7327+
dependencies:
7328+
string-width: ^4.2.0
7329+
strip-ansi: ^6.0.0
7330+
wrap-ansi: ^7.0.0
7331+
checksum: ce2e8f578a4813806788ac399b9e866297740eecd4ad1823c27fd344d78b22c5f8597d548adbcc46f0573e43e21e751f39446c5a5e804a12aace402b7a315d7f
7332+
languageName: node
7333+
linkType: hard
7334+
73127335
"cliui@npm:^8.0.1":
73137336
version: 8.0.1
73147337
resolution: "cliui@npm:8.0.1"
@@ -7870,6 +7893,15 @@ coolshapes-react@lowcoder-org/coolshapes-react:
78707893
languageName: node
78717894
linkType: hard
78727895

7896+
"cross-fetch@npm:4.1.0":
7897+
version: 4.1.0
7898+
resolution: "cross-fetch@npm:4.1.0"
7899+
dependencies:
7900+
node-fetch: ^2.7.0
7901+
checksum: c02fa85d59f83e50dbd769ee472c9cc984060c403ee5ec8654659f61a525c1a655eef1c7a35e365c1a107b4e72d76e786718b673d1cb3c97f61d4644cb0a9f9d
7902+
languageName: node
7903+
linkType: hard
7904+
78737905
"cross-fetch@npm:^3.1.5":
78747906
version: 3.1.8
78757907
resolution: "cross-fetch@npm:3.1.8"
@@ -14090,6 +14122,7 @@ coolshapes-react@lowcoder-org/coolshapes-react:
1409014122
"@types/regenerator-runtime": ^0.13.1
1409114123
"@types/uuid": ^8.3.4
1409214124
"@vitejs/plugin-react": ^2.2.0
14125+
alasql: ^4.6.2
1409314126
animate.css: ^4.1.1
1409414127
antd: ^5.20.0
1409514128
axios: ^1.7.7
@@ -15684,7 +15717,7 @@ coolshapes-react@lowcoder-org/coolshapes-react:
1568415717
languageName: node
1568515718
linkType: hard
1568615719

15687-
"node-fetch@npm:^2.6.12":
15720+
"node-fetch@npm:^2.6.12, node-fetch@npm:^2.7.0":
1568815721
version: 2.7.0
1568915722
resolution: "node-fetch@npm:2.7.0"
1569015723
dependencies:
@@ -22446,13 +22479,35 @@ coolshapes-react@lowcoder-org/coolshapes-react:
2244622479
languageName: node
2244722480
linkType: hard
2244822481

22482+
"yargs-parser@npm:^20.2.2":
22483+
version: 20.2.9
22484+
resolution: "yargs-parser@npm:20.2.9"
22485+
checksum: 8bb69015f2b0ff9e17b2c8e6bfe224ab463dd00ca211eece72a4cd8a906224d2703fb8a326d36fdd0e68701e201b2a60ed7cf81ce0fd9b3799f9fe7745977ae3
22486+
languageName: node
22487+
linkType: hard
22488+
2244922489
"yargs-parser@npm:^21.1.1":
2245022490
version: 21.1.1
2245122491
resolution: "yargs-parser@npm:21.1.1"
2245222492
checksum: ed2d96a616a9e3e1cc7d204c62ecc61f7aaab633dcbfab2c6df50f7f87b393993fe6640d017759fe112d0cb1e0119f2b4150a87305cc873fd90831c6a58ccf1c
2245322493
languageName: node
2245422494
linkType: hard
2245522495

22496+
"yargs@npm:16":
22497+
version: 16.2.0
22498+
resolution: "yargs@npm:16.2.0"
22499+
dependencies:
22500+
cliui: ^7.0.2
22501+
escalade: ^3.1.1
22502+
get-caller-file: ^2.0.5
22503+
require-directory: ^2.1.1
22504+
string-width: ^4.2.0
22505+
y18n: ^5.0.5
22506+
yargs-parser: ^20.2.2
22507+
checksum: b14afbb51e3251a204d81937c86a7e9d4bdbf9a2bcee38226c900d00f522969ab675703bee2a6f99f8e20103f608382936034e64d921b74df82b63c07c5e8f59
22508+
languageName: node
22509+
linkType: hard
22510+
2245622511
"yargs@npm:^17.3.1, yargs@npm:^17.5.1":
2245722512
version: 17.7.2
2245822513
resolution: "yargs@npm:17.7.2"

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy