Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d107b19

Browse files
committed
feat: openapi, n8n, dynamodb datasource
1 parent 353eaf1 commit d107b19

39 files changed

+6297
-85
lines changed

server/node-service/README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,11 @@ Write data source plugins with TypeScript.
77
### Develop
88

99
```bash
10-
yarn dev
10+
yarn && yarn dev
1111
```
1212

1313
### Production
1414

1515
```bash
16-
yarn build
17-
yarn start
16+
yarn && yarn build && yarn start
1817
```

server/node-service/jest.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ module.exports = {
33
preset: "ts-jest",
44
testEnvironment: "node",
55
testTimeout: 60000,
6+
testPathIgnorePatterns: ["/node_modules/", "/build/"],
67
};

server/node-service/package.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,35 +7,43 @@
77
},
88
"main": "src/server.ts",
99
"scripts": {
10-
"dev": "nodemon src/server.ts",
10+
"dev": "nodemon --files src/server.ts",
1111
"start": "node ./build/src/server.js",
1212
"test": "jest",
1313
"build": "rm -rf build/ && tsc && cp -r src/static build/src/static"
1414
},
1515
"devDependencies": {
1616
"@types/jest": "^29.2.4",
1717
"jest": "^29.3.1",
18+
"nock": "^13.3.0",
1819
"nodemon": "^2.0.20",
1920
"ts-jest": "^29.0.3",
2021
"ts-node": "^10.9.1"
2122
},
2223
"dependencies": {
24+
"@apidevtools/swagger-parser": "^10.1.0",
25+
"@aws-sdk/client-dynamodb": "^3.266.1",
2326
"@aws-sdk/client-s3": "^3.238.0",
2427
"@aws-sdk/s3-request-presigner": "^3.241.0",
2528
"@types/axios": "^0.14.0",
2629
"@types/express": "^4.17.14",
30+
"@types/jsonpath": "^0.2.0",
2731
"@types/lodash": "^4.14.190",
2832
"@types/morgan": "^1.9.3",
2933
"@types/node": "^18.11.18",
3034
"axios": "^1.2.0",
35+
"dynamodb-data-types": "^4.0.1",
3136
"express": "^4.18.2",
3237
"express-async-errors": "^3.1.1",
38+
"jsonpath": "^1.1.1",
3339
"lodash": "^4.17.21",
3440
"loglevel": "^1.8.1",
3541
"morgan": "^1.10.0",
42+
"openapi-types": "^12.1.0",
3643
"openblocks-core": "^0.0.5",
37-
"openblocks-sdk": "^0.0.30",
44+
"openblocks-sdk": "^0.0.34",
3845
"stylis": "^4.1.3",
46+
"swagger-client": "^3.18.5",
3947
"typescript": "^4.9.3"
4048
},
4149
"packageManager": "[email protected]"

server/node-service/src/api/queryApi.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const DEFAULT_EXECUTE_ACTION_TIMEOUT_MS = 15000;
77

88
type QueryExecuteRequest = {
99
libraryQueryName: string;
10-
params?: { key: string; value: string }[];
10+
params?: { key: string; value: any }[];
1111
};
1212

1313
export class QueryApi extends Api {

server/node-service/src/app-env.d.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
declare module "swagger-client" {
2+
const SwaggerClient: {
3+
helpers: {
4+
opId(operation: OpenAPI.Operation, path: string, method: string): string;
5+
};
6+
execute: any;
7+
};
8+
export default SwaggerClient;
9+
}

server/node-service/src/common/error.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@ export class ServiceError extends Error {
55
this.code = code;
66
}
77
}
8+
9+
export function badRequest(message: string) {
10+
return new ServiceError(message, 400);
11+
}

server/node-service/src/common/util.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { relaxedJSONToJSON } from "openblocks-core";
2+
13
export function toString(value: any): string {
24
if (value === undefined || value === null) {
35
return "";
@@ -37,3 +39,16 @@ export function toBoolean(value: any): boolean {
3739
}
3840
return !!value;
3941
}
42+
43+
export function toJsonValue(value: any): any {
44+
if (typeof value !== "string") {
45+
return value;
46+
}
47+
try {
48+
const json = relaxedJSONToJSON(value, true);
49+
return JSON.parse(json);
50+
} catch (e) {
51+
console.info("invalid json input:", value);
52+
return {};
53+
}
54+
}

server/node-service/src/controllers/plugins.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1+
import { badRequest } from "../common/error";
12
import { Request, Response } from "express";
23
import _ from "lodash";
4+
import { Config } from "openblocks-sdk/dataSource";
35
import * as pluginServices from "../services/plugin";
46

57
export async function listPlugins(req: Request, res: Response) {
8+
let ids = req.query["id"] || [];
9+
if (typeof ids === "string") {
10+
ids = [ids];
11+
}
612
const ctx = pluginServices.getPluginContext(req);
7-
const result = pluginServices.listPlugins(ctx);
13+
const result = pluginServices.listPlugins(ctx, ids as string[]);
814
return res.status(200).json(result);
915
}
1016

@@ -31,3 +37,28 @@ export async function validatePluginDataSourceConfig(req: Request, res: Response
3137
);
3238
return res.status(200).json(result);
3339
}
40+
41+
type GetDynamicDefReqBody = {
42+
pluginName: string;
43+
path: string;
44+
dataSourceConfig: any;
45+
}[];
46+
47+
export async function getDynamicDef(req: Request, res: Response) {
48+
const ctx = pluginServices.getPluginContext(req);
49+
if (!Array.isArray(req.body)) {
50+
throw badRequest("request body is not a valid array");
51+
}
52+
const fields = req.body as GetDynamicDefReqBody;
53+
const result: Config[] = [];
54+
for (const item of fields) {
55+
const def = await pluginServices.getDynamicConfigDef(
56+
item.pluginName,
57+
item.path,
58+
item.dataSourceConfig,
59+
ctx
60+
);
61+
result.push(def);
62+
}
63+
return res.status(200).json(result);
64+
}

server/node-service/src/controllers/runJavascript.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,17 @@ type BatchEvalResult = {
2222
};
2323

2424
async function evalJs(req: EvalRequest, cookie?: string): Promise<EvalResult> {
25-
const runQueryLibrary = (query: string) =>
26-
QueryApi.executeQuery({ libraryQueryName: query }, cookie).then((r) => {
25+
const runQueryLibrary = (query: string, params?: Record<string, any>) =>
26+
QueryApi.executeQuery(
27+
{
28+
libraryQueryName: query,
29+
params:
30+
typeof params === "object" && params !== null
31+
? Object.entries(params).map(([key, value]) => ({ key, value }))
32+
: undefined,
33+
},
34+
cookie
35+
).then((r) => {
2736
const data = r.data;
2837
if (data.success) {
2938
return Promise.resolve(data.data);
@@ -33,6 +42,7 @@ async function evalJs(req: EvalRequest, cookie?: string): Promise<EvalResult> {
3342
try {
3443
return { result: await evalFunc(req.jsCode || "", { ...req.context, runQueryLibrary }) };
3544
} catch (e) {
45+
console.error("get error when eval js:", e);
3646
return { error: getErrorMessage(e) };
3747
}
3848
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { ConfigToType } from "openblocks-sdk/dataSource";
2+
3+
const dataSourceConfig = {
4+
type: "dataSource",
5+
params: [
6+
{
7+
key: "accessKey",
8+
label: "Access key ID",
9+
type: "textInput",
10+
placeholder: "<Your Access key ID>",
11+
rules: [{ required: true, message: "Please input the Access Key ID" }],
12+
},
13+
{
14+
key: "secretKey",
15+
label: "Secret key",
16+
type: "password",
17+
rules: [{ required: true, message: "Please input the Secret Key" }],
18+
},
19+
{
20+
key: "endpointUrl",
21+
label: "Endpoint URL",
22+
type: "textInput",
23+
},
24+
{
25+
key: "region",
26+
type: "textInput",
27+
label: "Region",
28+
defaultValue: "us-west-1",
29+
},
30+
],
31+
} as const;
32+
33+
export default dataSourceConfig;
34+
35+
export type DataSourceDataType = ConfigToType<typeof dataSourceConfig>;
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { DataSourcePlugin } from "openblocks-sdk/dataSource";
2+
import dataSourceConfig, { DataSourceDataType } from "./dataSourceConfig";
3+
import queryConfig, { ActionDataType } from "./queryConfig";
4+
import { runDynamoDbQuery } from "./run";
5+
6+
const dynamoDBPlugin: DataSourcePlugin<ActionDataType, DataSourceDataType> = {
7+
id: "dynamodb",
8+
name: "DynamoDB",
9+
category: "database",
10+
icon: "dynamodb.svg",
11+
dataSourceConfig,
12+
queryConfig,
13+
run: async function (actionData, dataSourceConfig): Promise<any> {
14+
return runDynamoDbQuery(actionData, dataSourceConfig);
15+
},
16+
};
17+
18+
export default dynamoDBPlugin;
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import { ConfigToType } from "openblocks-sdk/dataSource";
2+
3+
const jsonParametersFieldConfig = (defaultValue: any) =>
4+
({
5+
key: "params",
6+
label: "Parameters",
7+
type: "jsonInput",
8+
defaultValue: JSON.stringify(defaultValue, null, 4),
9+
} as const);
10+
11+
const tableNameFieldConfig = {
12+
label: "Table",
13+
key: "tableName",
14+
type: "textInput",
15+
placeholder: "users",
16+
} as const;
17+
18+
const queryConfig = {
19+
type: "query",
20+
label: "Action",
21+
actions: [
22+
{
23+
actionName: "Query",
24+
label: "Query",
25+
params: [
26+
tableNameFieldConfig,
27+
jsonParametersFieldConfig({
28+
KeyConditionExpression: "id = :n",
29+
ExpressionAttributeValues: {
30+
":n": { N: "1" },
31+
},
32+
}),
33+
],
34+
},
35+
{
36+
actionName: "Scan",
37+
label: "Scan",
38+
params: [
39+
tableNameFieldConfig,
40+
jsonParametersFieldConfig({
41+
FilterExpression: "id > :n",
42+
ExpressionAttributeValues: {
43+
":n": { N: "0" },
44+
},
45+
}),
46+
],
47+
},
48+
{
49+
actionName: "PutItem",
50+
label: "Put item",
51+
params: [
52+
tableNameFieldConfig,
53+
jsonParametersFieldConfig({
54+
Item: {
55+
id: 1,
56+
name: "Alice",
57+
},
58+
}),
59+
],
60+
},
61+
{
62+
actionName: "GetItem",
63+
label: "Get item",
64+
params: [
65+
tableNameFieldConfig,
66+
jsonParametersFieldConfig({
67+
Key: {
68+
id: 1,
69+
},
70+
}),
71+
],
72+
},
73+
{
74+
actionName: "UpdateItem",
75+
label: "Update item",
76+
params: [
77+
tableNameFieldConfig,
78+
jsonParametersFieldConfig({
79+
Key: {
80+
id: 1,
81+
},
82+
UpdateExpression: "set age = :n",
83+
ExpressionAttributeValues: {
84+
":n": {
85+
N: "18",
86+
},
87+
},
88+
}),
89+
],
90+
},
91+
{
92+
actionName: "DeleteItem",
93+
label: "Delete item",
94+
params: [
95+
tableNameFieldConfig,
96+
jsonParametersFieldConfig({
97+
Key: {
98+
id: 1,
99+
},
100+
}),
101+
],
102+
},
103+
{
104+
actionName: "ListTables",
105+
label: "List tables",
106+
params: [
107+
jsonParametersFieldConfig({
108+
Limit: 10,
109+
}),
110+
],
111+
},
112+
{
113+
actionName: "CreateTable",
114+
label: "Create table",
115+
params: [
116+
jsonParametersFieldConfig({
117+
TableName: "users",
118+
AttributeDefinitions: [
119+
{
120+
AttributeName: "id",
121+
AttributeType: "N",
122+
},
123+
],
124+
KeySchema: [
125+
{
126+
AttributeName: "id",
127+
KeyType: "HASH",
128+
},
129+
],
130+
ProvisionedThroughput: {
131+
ReadCapacityUnits: 1,
132+
WriteCapacityUnits: 1,
133+
},
134+
StreamSpecification: {
135+
StreamEnabled: false,
136+
},
137+
}),
138+
],
139+
},
140+
],
141+
} as const;
142+
143+
export type ActionDataType = ConfigToType<typeof queryConfig>;
144+
145+
export default queryConfig;

0 commit comments

Comments
 (0)