Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite7a58b0

Browse files
authored
Merge pull requestlowcoder-org#914 from dswbx/feature/turso
Added turso as a data source plugin
2 parents2aef1f3 +bd2d6e1 commite7a58b0

File tree

3 files changed

+198
-1
lines changed

3 files changed

+198
-1
lines changed

‎server/node-service/src/plugins/index.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import huggingFaceInferencePlugin from "./huggingFaceInference";
3333
importdidPluginfrom"./did";
3434
importbigQueryPluginfrom"./bigQuery";
3535
importappConfigPluginfrom"./appconfig";
36+
importtursoPluginfrom"./turso";
3637

3738
letplugins:(DataSourcePlugin|DataSourcePluginFactory)[]=[
3839
s3Plugin,
@@ -68,7 +69,8 @@ let plugins: (DataSourcePlugin | DataSourcePluginFactory)[] = [
6869
faunaPlugin,
6970
didPlugin,
7071
bigQueryPlugin,
71-
appConfigPlugin
72+
appConfigPlugin,
73+
tursoPlugin,
7274
];
7375

7476
try{
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
import{DataSourcePlugin,PluginContext}from"lowcoder-sdk/dataSource";
2+
import_from"lodash";
3+
import{ServiceError}from"../../common/error";
4+
import{ConfigToType}from"lowcoder-sdk/dataSource";
5+
6+
constdataSourceConfig={
7+
type:"dataSource",
8+
params:[
9+
{
10+
key:"url",
11+
type:"textInput",
12+
label:"URL",
13+
tooltip:"e.g. https://db-company.turso.io",
14+
placeholder:"<Your Turso URL>",
15+
rules:[{required:true,message:"Please add the URL to your database"}]
16+
},
17+
{
18+
key:"token",
19+
label:"Token",
20+
type:"password",
21+
placeholder:"<Your Token>",
22+
rules:[{required:true,message:"Please input the token"}],
23+
}
24+
],
25+
}asconst;
26+
typeDataSourceDataType=ConfigToType<typeofdataSourceConfig>;
27+
28+
constqueryConfig={
29+
type:"query",
30+
label:"Action",
31+
actions:[
32+
{
33+
actionName:"Query",
34+
label:"Query",
35+
params:[
36+
{
37+
label:"Query String",
38+
key:"queryString",
39+
type:"sqlInput",
40+
},
41+
{
42+
label:"Include raw",
43+
key:"includeRaw",
44+
tooltip:"Include raw information in the response",
45+
type:"switch"
46+
}
47+
],
48+
},
49+
],
50+
}asconst;
51+
typeActionDataType=ConfigToType<typeofqueryConfig>;
52+
53+
// from https://github.com/tursodatabase/libsql/blob/main/docs/HRANA_3_SPEC.md#hrana-over-http
54+
typeRow={
55+
type:"integer"|"text"|"float"|"blob"|"null";
56+
value?:string;
57+
};
58+
typeCol={
59+
name:string;
60+
decltype:string;
61+
}
62+
typeResultSet={
63+
cols:Col[];
64+
rows:Row[][];
65+
affected_row_count:number;
66+
last_insert_rowid:number|null;
67+
replication_index:string;
68+
rows_read:number;
69+
rows_written:number;
70+
query_duration_ms:number;
71+
}
72+
typeResult={
73+
type:"ok"
74+
response:{
75+
type:"execute"|"close"|string;
76+
result:ResultSet
77+
}
78+
}|{
79+
type:"error";
80+
error:any
81+
};
82+
83+
typeResponse={
84+
baton:string|null;
85+
base_url:string|null;
86+
results:Result[];
87+
}
88+
89+
consttursoPlugin:DataSourcePlugin<ActionDataType,DataSourceDataType>={
90+
id:"turso",
91+
name:"Turso",
92+
category:"database",
93+
icon:"turso.svg",
94+
dataSourceConfig,
95+
queryConfig,
96+
run:asyncfunction(actionData,dataSourceConfig,ctx:PluginContext):Promise<any>{
97+
const{url:_url, token}=dataSourceConfig;
98+
consturl=_url.replace("libsql://","https://");
99+
const{ queryString, includeRaw}=actionData;
100+
101+
constresult=awaitfetch(`${url}/v2/pipeline`,{
102+
method:"POST",
103+
headers:{
104+
"Content-Type":"application/json",
105+
"Authorization":`Bearer${token}`
106+
},
107+
body:JSON.stringify({
108+
requests:[
109+
{type:"execute",stmt:{sql:queryString}},
110+
{type:"close"}
111+
]
112+
})
113+
})
114+
115+
if(!result.ok){
116+
thrownewServiceError(`Failed to execute query. Endpoint returned${result.status}:${result.statusText}.`);
117+
}
118+
119+
constdata=awaitresult.json()asResponse;
120+
constparsed=parseResult(data.results[0]);
121+
122+
returnincludeRaw ?parsed :parsed?.values;
123+
},
124+
};
125+
126+
127+
functionparseValue(val:Col&Row):{[key:string]:any}{
128+
constname=val.name;
129+
letvalue:any=val.value;
130+
131+
switch(true){
132+
caseval.type==="integer"&&val.decltype==="boolean":
133+
value=Boolean(Number.parseInt(value));
134+
break;
135+
caseval.type==="integer":
136+
value=Number.parseInt(value);
137+
break;
138+
caseval.type==="float":
139+
value=Number.parseFloat(value);
140+
break;
141+
case["datetime","date"].includes(val.decltype)&&val.type==="text"&&!!value:
142+
value=newDate(value);
143+
break;
144+
caseval.type==="null":
145+
value=null;
146+
break;
147+
}
148+
149+
return{
150+
[name]:value,
151+
};
152+
}
153+
154+
functionparseResult(
155+
result:Result
156+
):{raw:ResultSet;values:Record<string,any>}|undefined{
157+
if(result.type==="error"){
158+
thrownewServiceError(`Cannot parse result, received error:${result.error}`);
159+
}
160+
161+
constres=result.response.result;
162+
if(!res)return;
163+
164+
constcombined:(Col&Row)[][]=res.rows.map((row)=>
165+
row.map((col,i)=>({
166+
...col,
167+
...res.cols[i],
168+
}))
169+
);
170+
171+
constvalues:any[]=[];
172+
for(letrowofcombined){
173+
values.push(
174+
row.reduce((acc,curr)=>({ ...acc, ...parseValue(curr)}),{})
175+
);
176+
}
177+
178+
return{
179+
values,
180+
raw:res,
181+
};
182+
}
183+
184+
exportdefaulttursoPlugin;
Lines changed: 11 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp